Selaa lähdekoodia

Implemented correct handling of inherited methods.

- symtable.pas:
* I extended "searchsym_in_class" with a parameter to decide whether helpers should be searched before the normal class' methods, after them or not at all (as I'm not using that anymore, I might revert this to a simple Boolean again)
* Added a new function "searchsym_in_helper" which implements the algorithm to search for a symbol inside a helper's implementation. For more information on this algorithm please read the comment at the top of that function ("searchsym_in_class" also calls this function in the case that "classh" is a helper)
- pexpr.pas:
* fixes for extended "searchsym_in_class"
* in case of "inherited" and a helper the new "searchsym_in_helper" is called with the "hasinherited" parameter set to true
- pinline.pas:
fixes for extended "searchsym_in_class"
- symconst.pas:
added new enumeration for helper search order (might be removed again)

git-svn-id: branches/svenbarth/classhelpers@17070 -
svenbarth 14 vuotta sitten
vanhempi
commit
878c8c7806
4 muutettua tiedostoa jossa 126 lisäystä ja 33 poistoa
  1. 15 9
      compiler/pexpr.pas
  2. 1 1
      compiler/pinline.pas
  3. 6 0
      compiler/symconst.pas
  4. 104 23
      compiler/symtable.pas

+ 15 - 9
compiler/pexpr.pas

@@ -1031,7 +1031,7 @@ implementation
             else
              static_name:=lower(generate_nested_name(sym.owner,'_'))+'_'+sym.name;
             if sym.owner.defowner.typ=objectdef then
-              searchsym_in_class(tobjectdef(sym.owner.defowner),tobjectdef(sym.owner.defowner),static_name,sym,srsymtable,true)
+              searchsym_in_class(tobjectdef(sym.owner.defowner),tobjectdef(sym.owner.defowner),static_name,sym,srsymtable,hs_searchfirst)
             else
               searchsym_in_record(trecorddef(sym.owner.defowner),static_name,sym,srsymtable);
             if assigned(sym) then
@@ -1508,7 +1508,7 @@ implementation
                              begin
                                p1:=ctypenode.create(hdef);
                                { search also in inherited methods }
-                               searchsym_in_class(tobjectdef(hdef),tobjectdef(current_structdef),pattern,srsym,srsymtable,true);
+                               searchsym_in_class(tobjectdef(hdef),tobjectdef(current_structdef),pattern,srsym,srsymtable,hs_searchfirst);
                                if assigned(srsym) then
                                  check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg);
                                consume(_ID);
@@ -2141,7 +2141,7 @@ implementation
                            if token=_ID then
                              begin
                                structh:=tobjectdef(tclassrefdef(p1.resultdef).pointeddef);
-                               searchsym_in_class(tobjectdef(structh),tobjectdef(structh),pattern,srsym,srsymtable,true);
+                               searchsym_in_class(tobjectdef(structh),tobjectdef(structh),pattern,srsym,srsymtable,hs_searchfirst);
                                if assigned(srsym) then
                                  begin
                                    check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg);
@@ -2165,7 +2165,7 @@ implementation
                            if token=_ID then
                              begin
                                structh:=tobjectdef(p1.resultdef);
-                               searchsym_in_class(tobjectdef(structh),tobjectdef(structh),pattern,srsym,srsymtable,true);
+                               searchsym_in_class(tobjectdef(structh),tobjectdef(structh),pattern,srsym,srsymtable,hs_searchfirst);
                                if assigned(srsym) then
                                  begin
                                     check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg);
@@ -2388,8 +2388,11 @@ implementation
                         if (po_msgstr in pd.procoptions) then
                           searchsym_in_class_by_msgstr(hclassdef,pd.messageinf.str^,srsym,srsymtable)
                        else
-                         { disable search for helpers }
-                         searchsym_in_class(hclassdef,tobjectdef(current_structdef),hs,srsym,srsymtable,false);
+                       { helpers have their own ways of dealing with inherited }
+                       if is_objectpascal_helper(current_structdef) then
+                         searchsym_in_helper(tobjectdef(current_structdef),tobjectdef(current_structdef),hs,srsym,srsymtable,true)
+                       else
+                         searchsym_in_class(hclassdef,tobjectdef(current_structdef),hs,srsym,srsymtable,hs_nosearch);
                      end
                     else
                      begin
@@ -2397,8 +2400,11 @@ implementation
                        hsorg:=orgpattern;
                        consume(_ID);
                        anon_inherited:=false;
-                       { disable search for helpers }
-                       searchsym_in_class(hclassdef,tobjectdef(current_structdef),hs,srsym,srsymtable,false);
+                       { helpers have their own ways of dealing with inherited }
+                       if is_objectpascal_helper(current_structdef) then
+                         searchsym_in_helper(tobjectdef(current_structdef),tobjectdef(current_structdef),hs,srsym,srsymtable,true)
+                       else
+                         searchsym_in_class(hclassdef,tobjectdef(current_structdef),hs,srsym,srsymtable,hs_nosearch);
                      end;
                     if assigned(srsym) then
                      begin
@@ -2432,7 +2438,7 @@ implementation
                           if (po_msgint in pd.procoptions) or
                              (po_msgstr in pd.procoptions) then
                             begin
-                              searchsym_in_class(hclassdef,hclassdef,'DEFAULTHANDLER',srsym,srsymtable,true);
+                              searchsym_in_class(hclassdef,hclassdef,'DEFAULTHANDLER',srsym,srsymtable,hs_searchfirst);
                               if not assigned(srsym) or
                                  (srsym.typ<>procsym) then
                                 internalerror(200303171);

+ 1 - 1
compiler/pinline.pas

@@ -434,7 +434,7 @@ implementation
             { search the constructor also in the symbol tables of
               the parents }
             afterassignment:=false;
-            searchsym_in_class(classh,classh,pattern,srsym,srsymtable,true);
+            searchsym_in_class(classh,classh,pattern,srsym,srsymtable,hs_searchfirst);
             consume(_ID);
             do_member_read(classh,false,srsym,p1,again,[cnf_new_call]);
             { we need to know which procedure is called }

+ 6 - 0
compiler/symconst.pas

@@ -338,6 +338,12 @@ type
     ht_record
   );
 
+  { defines when helper methods should be searched }
+  thelpersearch=(hs_nosearch, { helper methods are not searched at all }
+    hs_searchfirst,           { search before the actual extended types symbols }
+    hs_searchlast             { search only if no symbol is found in the extended type }
+  );
+
   { Variations in interfaces implementation }
   { Beware, this data is duplicated in the compiler and rtl. }
   { Do not change the order of the fields. }

+ 104 - 23
compiler/symtable.pas

@@ -220,10 +220,11 @@ interface
     function  searchsym_type(const s : TIDString;out srsym:tsym;out srsymtable:TSymtable):boolean;
     function  searchsym_in_module(pm:pointer;const s : TIDString;out srsym:tsym;out srsymtable:TSymtable):boolean;
     function  searchsym_in_named_module(const unitname, symname: TIDString; out srsym: tsym; out srsymtable: tsymtable): boolean;
-    function  searchsym_in_class(classh,contextclassh:tobjectdef;const s : TIDString;out srsym:tsym;out srsymtable:TSymtable;searchhelper:boolean):boolean;
+    function  searchsym_in_class(classh,contextclassh:tobjectdef;const s : TIDString;out srsym:tsym;out srsymtable:TSymtable;searchhelper:thelpersearch):boolean;
     function  searchsym_in_record(recordh:tabstractrecorddef;const s : TIDString;out srsym:tsym;out srsymtable:TSymtable):boolean;
     function  searchsym_in_class_by_msgint(classh:tobjectdef;msgid:longint;out srdef : tdef;out srsym:tsym;out srsymtable:TSymtable):boolean;
     function  searchsym_in_class_by_msgstr(classh:tobjectdef;const s:string;out srsym:tsym;out srsymtable:TSymtable):boolean;
+    function  searchsym_in_helper(classh,contextclassh:tobjectdef;const s: TIDString;out srsym:tsym;out srsymtable:TSymtable;aHasInherited:boolean):boolean;
     function  search_system_type(const s: TIDString): ttypesym;
     function  search_named_unit_globaltype(const unitname, typename: TIDString; throwerror: boolean): ttypesym;
     function  search_struct_member(pd : tabstractrecorddef;const s : string):tsym;
@@ -1906,7 +1907,7 @@ implementation
             srsymtable:=stackitem^.symtable;
             if (srsymtable.symtabletype=objectsymtable) then
               begin
-                if searchsym_in_class(tobjectdef(srsymtable.defowner),tobjectdef(srsymtable.defowner),s,srsym,srsymtable,true) then
+                if searchsym_in_class(tobjectdef(srsymtable.defowner),tobjectdef(srsymtable.defowner),s,srsym,srsymtable,hs_searchfirst) then
                   begin
                     result:=true;
                     exit;
@@ -2136,7 +2137,7 @@ implementation
       end;
 
 
-    function searchsym_in_class(classh,contextclassh:tobjectdef;const s : TIDString;out srsym:tsym;out srsymtable:TSymtable;searchhelper:boolean):boolean;
+    function searchsym_in_class(classh,contextclassh:tobjectdef;const s : TIDString;out srsym:tsym;out srsymtable:TSymtable;searchhelper:thelpersearch):boolean;
       var
         hashedid : THashedIDString;
         exdef    : tabstractrecorddef;
@@ -2145,7 +2146,7 @@ implementation
       begin
         { search for a class helper method first if this is an Object Pascal
           class }
-        if is_class(classh) and searchhelper then
+        if is_class(classh) and (searchhelper = hs_searchfirst) then
           begin
             result:=search_objectpascal_class_helper(classh,contextclassh,s,srsym,srsymtable);
             if result then
@@ -2189,33 +2190,23 @@ implementation
               end;
             for i:=0 to classh.ImplementedInterfaces.count-1 do
               begin
-                if searchsym_in_class(TImplementedInterface(classh.ImplementedInterfaces[i]).intfdef,contextclassh,s,srsym,srsymtable,true) then
+                if searchsym_in_class(TImplementedInterface(classh.ImplementedInterfaces[i]).intfdef,contextclassh,s,srsym,srsymtable,hs_nosearch) then
                   begin
                     result:=true;
                     exit;
                   end;
               end;
           end
+        else
+        if is_objectpascal_helper(classh) then
+          begin
+            { helpers have their own obscure search logic... }
+            result:=searchsym_in_helper(classh,contextclassh,s,srsym,srsymtable,false);
+            if result then
+              exit;
+          end
         else
           begin
-            { if we're searching for a symbol inside a helper, we must search in
-              the extended class/record/whatever first }
-            if is_objectpascal_helper(classh) then
-              begin
-                { important: disable the search for helpers here! }
-                if is_class(classh.extendeddef) and
-                    searchsym_in_class(tobjectdef(classh.extendeddef), tobjectdef(classh.extendeddef), s, srsym, srsymtable, false) then
-                  begin
-                    result:=true;
-                    exit;
-                  end
-                else if is_record(classh.extendeddef) and
-                    searchsym_in_record(classh.extendeddef, s, srsym, srsymtable) then
-                  begin
-                    result:=true;
-                    exit;
-                  end;
-              end;
             while assigned(classh) do
               begin
                 srsymtable:=classh.symtable;
@@ -2232,6 +2223,10 @@ implementation
           end;
         if is_objcclass(orgclass) then
           result:=search_class_helper(orgclass,s,srsym,srsymtable)
+        else
+        { this is currently not used, so maybe this can be removed again... }
+        if is_class(orgclass) and (searchhelper = hs_searchlast) then
+          result:=search_objectpascal_class_helper(orgclass,contextclassh,s,srsym,srsymtable)
         else
           begin
             srsym:=nil;
@@ -2329,6 +2324,92 @@ implementation
         srsymtable:=nil;
       end;
 
+    function searchsym_in_helper(classh,contextclassh:tobjectdef;const s: TIDString;out srsym:tsym;out srsymtable:TSymtable;aHasInherited:boolean):boolean;
+      var
+        hashedid      : THashedIDString;
+        tmpsrsym      : tsym;
+        tmpsrsymtable : tsymtable;
+        found         : boolean;
+      begin
+        if not is_objectpascal_helper(classh) then
+          Internalerror(2011030101);
+        hashedid.id:=s;
+        if is_class(classh.extendeddef) then
+          begin
+            { in a class helper things are a bit more complex:
+              1. search the symbol in the helper (if not "inherited")
+              2. search the symbol in the extended type
+              3. search the symbol in the parent helpers
+              4. search the symbol in the parents of the extended type
+              Thus we search in the hierarchy of the extended type first and
+              check whether the returned symtable (if any) belongs to the
+              extended type or one of its parents. If the latter we first
+              check whether one of the helper parents contains a suitable
+              symbol
+            }
+            if not aHasInherited then
+              begin
+                { search in the helper itself }
+                srsymtable:=classh.symtable;
+                srsym:=tsym(srsymtable.FindWithHash(hashedid));
+                if assigned(srsym) and
+                   is_visible_for_object(srsym,contextclassh) then
+                  begin
+                    addsymref(srsym);
+                    result:=true;
+                    exit;
+                  end;
+              end;
+            { search in the hierarchy of the extended class }
+            found:=searchsym_in_class(tobjectdef(classh.extendeddef),tobjectdef(classh.extendeddef),s,tmpsrsym,tmpsrsymtable,hs_nosearch);
+            if not found then
+              begin
+                if assigned(classh.childof) then
+                  begin
+                    { the symbol isn't in the extended type's hierarchy,
+                      so search in the parents of the helper }
+                    result:=searchsym_in_class(classh.childof,contextclassh,s,srsym,srsymtable,hs_nosearch);
+                    if result and is_visible_for_object(srsym,contextclassh) then
+                      addsymref(srsym);
+                  end;
+              end
+            else
+              begin
+                if (tmpsrsymtable.defowner=classh.extendeddef) and
+                    is_visible_for_object(tmpsrsym,contextclassh) then
+                  begin
+                    { the symbol was found in the extended type }
+                    result:=true;
+                    srsym:=tmpsrsym;
+                    srsymtable:=tmpsrsymtable;
+                    exit;
+                  end
+                else
+                  begin
+                    result:=false;
+                    { search in the helper's parents first }
+                    if assigned(classh.childof) then
+                      result:=searchsym_in_class(classh.childof,contextclassh,s,srsym,srsymtable,hs_nosearch);
+                    if not result then
+                      begin
+                        { we use the symbol found in one of the extended
+                          type's ancestors }
+                        result:=true;
+                        srsym:=tmpsrsym;
+                        srsymtable:=tmpsrsymtable;
+                      end;
+                    if assigned(srsym) and is_visible_for_object(srsym,contextclassh) then
+                      addsymref(srsym);
+                  end;
+              end;
+          end
+        else if is_record(classh.extendeddef) and
+            searchsym_in_record(classh.extendeddef, s, srsym, srsymtable) then
+          begin
+            result:=true;
+            exit;
+          end;
+      end;
 
     function search_specific_assignment_operator(assignment_type:ttoken;from_def,to_def:Tdef):Tprocdef;
       var