m3tk/src/warn/M3CChkObsolete.m3


 Copyright (C) 1992, Digital Equipment Corporation           
 All rights reserved.                                        
 See the file COPYRIGHT for a full description.              

MODULE M3CChkObsolete;

IMPORT PropertyV;

IMPORT ASTWalk;
IMPORT AST, M3AST_AS;
IMPORT M3Error, M3CPragma;
IMPORT SeqM3AST_AS_DEF_ID, SeqM3AST_AS_Used_interface_id;
IMPORT M3AST_AS_F, M3AST_SM_F, M3AST_TM_F, M3AST_TL_F;

REVEAL
  Handle = ASTWalk.Closure BRANDED OBJECT
  OVERRIDES callback := Node;
  END; (* record *)

PROCEDURE Node(
    <*UNUSED*> h: Handle;
    n: AST.NODE;
    vm: ASTWalk.VisitMode)
    RAISES {}=
  VAR used_id: M3AST_AS.USED_ID;
  BEGIN
    IF vm = ASTWalk.VisitMode.Entry THEN
      IF n.IsA_USED_ID(used_id) THEN
        TYPECASE used_id.sm_def OF
        | NULL => (* not bound *)
        | M3AST_AS.DEF_ID(d) =>
            (* Now we can look at the pre-computed set of
               OBSOLETE DEF_IDs in "d.tmp_unit_id" *)
            IF IsObsolete(d) THEN
              M3Error.WarnWithId(used_id, "%s is OBSOLETE", used_id.lx_symrep);
            END;
        END;
      END;
    END;
  END Node;

PROCEDURE NewHandle(cu: M3AST_AS.Compilation_Unit): Handle RAISES {}=
  BEGIN
    (* Set up information on OBSOLETE declarations for this unit,
       and all imported ones. *)
    TYPECASE cu.as_root OF
    | NULL =>
    | M3AST_AS.UNIT_NORMAL(unit) =>
        SetupDefIds(cu);
        VAR iter := SeqM3AST_AS_Used_interface_id.NewIter(unit.sm_import_s);
            used_id: M3AST_AS.Used_interface_id;
        BEGIN
          WHILE SeqM3AST_AS_Used_interface_id.Next(iter, used_id) DO
            TYPECASE used_id.sm_def OF
            | NULL =>
            | M3AST_AS.UNIT_ID(unit_id)=>
                SetupDefIds(unit_id.sm_spec.sm_comp_unit);
            ELSE
            END;
          END;
        END
    ELSE
    END;
    RETURN NEW(Handle);
  END NewHandle;

PROCEDURE SetupDefIds(cu: M3AST_AS.Compilation_Unit)=
  VAR iter := M3CPragma.NewIter(cu.lx_pragmas);
      pragma: M3CPragma.T;
      args: TEXT;
      follower: M3AST_AS.SRC_NODE;
      bad: BOOLEAN;
  BEGIN
    IF GetSeq(cu) # NIL THEN RETURN END;

    WITH usd = NEW(UniqSeqM3AST_AS_DEF_ID) DO
      PropertyV.Put(cu.tl_pset, usd);
      WHILE M3CPragma.Next(iter, pragma) DO
        IF M3CPragma.Match(pragma, "OBSOLETE", args) THEN
          follower := M3CPragma.FollowingNode(pragma);
          bad := FALSE;
          TYPECASE follower OF
          | NULL => bad := TRUE;
          | M3AST_AS.DECL_REVL(d) =>
              <*FATAL ANY*> BEGIN
                ASTWalk.VisitNodes(d, NEW(SetupClosure, rs := usd));
              END;
          ELSE bad := TRUE
          END;
          IF bad THEN M3Error.ReportAtPos(M3CPragma.Position(pragma),
              "OBSOLETE must precede a declaration or revelation");
          END;
        END;
      END;
    END;
  END SetupDefIds;

TYPE SetupClosure = ASTWalk.Closure OBJECT
    rs: UniqSeqM3AST_AS_DEF_ID;
  OVERRIDES callback := Setup
  END;

  UniqSeqM3AST_AS_DEF_ID = BRANDED REF SeqM3AST_AS_DEF_ID.T;

PROCEDURE Setup(cl: SetupClosure; n: AST.NODE; <*UNUSED*> vm: ASTWalk.VisitMode)=
  BEGIN
    TYPECASE n OF
    | M3AST_AS.DEF_ID(d) =>
        SeqM3AST_AS_DEF_ID.AddFront(cl.rs^, d);
    ELSE
    END;
  END Setup;

PROCEDURE IsObsolete(d: M3AST_AS.DEF_ID): BOOLEAN=
  BEGIN
    WITH cu = d.tmp_unit_id.sm_spec.sm_comp_unit DO
      VAR iter := SeqM3AST_AS_DEF_ID.NewIter(GetSeq(cu)^);
        od: M3AST_AS.DEF_ID;
      BEGIN
        WHILE SeqM3AST_AS_DEF_ID.Next(iter, od) DO
          IF d = od THEN RETURN TRUE END;
        END;
      END;
    END;
    RETURN FALSE;
  END IsObsolete;

PROCEDURE GetSeq(cu: M3AST_AS.Compilation_Unit): UniqSeqM3AST_AS_DEF_ID=
  BEGIN
    RETURN PropertyV.Get(cu.tl_pset, TYPECODE(UniqSeqM3AST_AS_DEF_ID));
  END GetSeq;

BEGIN

END M3CChkObsolete.