# HG changeset patch # User Danila Sergeyev # Date 1432219104 -14400 # Node ID 46b969827ca9bcc0263f1228575754907f837560 # Parent d7107cd01f2af0e9b653e41fe494d1f10c9f525b bug #196979 Extend the callgraph feature for structure/class elements and global variables diff --git a/cnd.callgraph/src/org/netbeans/modules/cnd/callgraph/api/Function.java b/cnd.callgraph/src/org/netbeans/modules/cnd/callgraph/api/Function.java --- a/cnd.callgraph/src/org/netbeans/modules/cnd/callgraph/api/Function.java +++ b/cnd.callgraph/src/org/netbeans/modules/cnd/callgraph/api/Function.java @@ -88,4 +88,6 @@ * Open function in editor */ void open(); + + boolean isFunction(); } diff --git a/cnd.callgraph/src/org/netbeans/modules/cnd/callgraph/impl/CallGraphScene.java b/cnd.callgraph/src/org/netbeans/modules/cnd/callgraph/impl/CallGraphScene.java --- a/cnd.callgraph/src/org/netbeans/modules/cnd/callgraph/impl/CallGraphScene.java +++ b/cnd.callgraph/src/org/netbeans/modules/cnd/callgraph/impl/CallGraphScene.java @@ -4,12 +4,16 @@ package org.netbeans.modules.cnd.callgraph.impl; +import java.awt.BasicStroke; +import java.awt.Color; import org.netbeans.modules.cnd.callgraph.support.HorizontalHierarchicalLayout; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics2D; +import java.awt.Image; import java.awt.Point; import java.awt.Rectangle; +import java.awt.Stroke; import java.awt.event.ActionEvent; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; @@ -265,14 +269,10 @@ } String scope = node.getScopeName(); Widget label; - if (scope != null && scope.length() > 0){ - if (name.startsWith(scope)) { - name = name.substring(scope.length()); - } - label = new MyMemberLabelWidget(this, scope, name); - } else { - label = new MyLabelWidget(this, name); + if (name.startsWith(scope)) { + name = name.substring(scope.length()); } + label = new MyMemberLabelWidget(this, scope, name, node.getIcon()); if (node.isVurtual()) { label.setFont(defaultItalicFont); } @@ -289,6 +289,10 @@ @Override protected Widget attachEdgeWidget(Call edge) { ConnectionWidget connection = new ConnectionWidget(this); + if (!edge.getCallee().isFunction()) { + float dash[] = { 10.0f }; + connection.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dash, 0.0f)); + } connection.setToolTipText(edge.getDescription()); connection.setTargetAnchorShape(AnchorShape.TRIANGLE_FILLED); connection.getActions().addAction(hoverAction); @@ -338,31 +342,18 @@ } } - private static final class MyLabelWidget extends LabelWidget { - public MyLabelWidget (Scene scene, String label) { - super(scene); - setFont(scene.getFont().deriveFont(Font.BOLD)); - setLabel(label); - } - - @Override - protected void notifyStateChanged(ObjectState previousState, ObjectState state) { - if (previousState.isHovered() == state.isHovered()) { - return; - } - setForeground(getScene().getLookFeel().getLineColor(state)); - repaint(); - } - } - private static final class MyMemberLabelWidget extends Widget { + private static final int ICON_X_OFFSET = 3; // 3 px offset between icon and var name + private String scope; private String label; + private final Image icon; - public MyMemberLabelWidget (Scene scene, String scope, String label) { + public MyMemberLabelWidget (Scene scene, String scope, String label, Image icon) { super (scene); this.scope = scope; this.label = label; + this.icon = icon; setOpaque(false); revalidate(); setCheckClipping(true); @@ -379,13 +370,31 @@ @Override protected Rectangle calculateClientArea () { + return (scope != null && scope.length() > 0) ? calculateClientAreaWithScope() : calculateClientAreaWithoutScope(); + } + + private Rectangle calculateClientAreaWithScope() { Graphics2D gr = getGraphics(); Rectangle2D stringBounds1 = gr.getFontMetrics(getFont()).getStringBounds(scope, gr); Rectangle2D stringBounds2 = gr.getFontMetrics(getFont().deriveFont(Font.BOLD)).getStringBounds(label, gr); - Rectangle2D stringBounds = new Rectangle2D.Double(stringBounds1.getX(), stringBounds1.getY(), - Math.max(stringBounds1.getWidth(), stringBounds2.getWidth()), stringBounds1.getHeight()+stringBounds2.getHeight()); + int iconWidth = icon.getWidth(null) + ICON_X_OFFSET; + Rectangle2D stringBounds = new Rectangle2D.Double( stringBounds1.getX(), + stringBounds1.getY(), + Math.max(stringBounds1.getWidth(), stringBounds2.getWidth()) + iconWidth, + stringBounds1.getHeight()+Math.max(icon.getHeight(null), stringBounds2.getHeight()) ); return roundRectangle(stringBounds); } + + private Rectangle calculateClientAreaWithoutScope() { + Graphics2D gr = getGraphics(); + Rectangle2D stringBounds = gr.getFontMetrics(getFont().deriveFont(Font.BOLD)).getStringBounds(label, gr); + int iconWidth = icon.getWidth(null) + ICON_X_OFFSET; + Rectangle2D newStringBounds = new Rectangle2D.Double( stringBounds.getX(), + stringBounds.getY(), + stringBounds.getWidth() + iconWidth, + Math.max(icon.getHeight(null), stringBounds.getHeight()) ); + return roundRectangle(newStringBounds); + } private static Rectangle roundRectangle (Rectangle2D rectangle) { int x1 = (int) Math.floor(rectangle.getX()); @@ -397,9 +406,6 @@ @Override protected void paintWidget () { - if (label == null) { - return; - } Graphics2D gr = getGraphics(); gr.setFont(getFont()); @@ -411,10 +417,20 @@ AffineTransform previousTransform = gr.getTransform (); gr.translate (x, y); gr.setColor(getForeground()); - gr.drawString (scope, 0, 0); - gr.setFont(getFont().deriveFont(Font.BOLD)); - gr.drawString (label, 0, fontMetrics.getHeight()); - gr.setTransform(previousTransform); + if (scope != null && scope.length() > 0) { + gr.drawString (scope, 0, 0); + gr.setFont(getFont().deriveFont(Font.BOLD)); + gr.drawString (label, icon.getWidth(null) + ICON_X_OFFSET, fontMetrics.getHeight()); + gr.setTransform(previousTransform); + gr.drawImage(icon, 0, icon.getHeight(null) - fontMetrics.getHeight(), null); + } else { + int iconYOffset = gr.getFont().getSize() - icon.getHeight(null); + int textYOffset = icon.getHeight(null) - fontMetrics.getHeight(); + gr.setFont(getFont().deriveFont(Font.BOLD)); + gr.drawString (label, icon.getWidth(null) + ICON_X_OFFSET, textYOffset); + gr.setTransform(previousTransform); + gr.drawImage(icon, 0, -(iconYOffset + fontMetrics.getHeight()), null); + } } } diff --git a/cnd.navigation/src/org/netbeans/modules/cnd/navigation/callgraph/CallGraphModelFactoryImpl.java b/cnd.navigation/src/org/netbeans/modules/cnd/navigation/callgraph/CallGraphModelFactoryImpl.java --- a/cnd.navigation/src/org/netbeans/modules/cnd/navigation/callgraph/CallGraphModelFactoryImpl.java +++ b/cnd.navigation/src/org/netbeans/modules/cnd/navigation/callgraph/CallGraphModelFactoryImpl.java @@ -48,7 +48,9 @@ import org.netbeans.modules.cnd.api.model.CsmFile; import org.netbeans.modules.cnd.api.model.CsmFunction; import org.netbeans.modules.cnd.api.model.CsmObject; +import org.netbeans.modules.cnd.api.model.CsmOffsetableDeclaration; import org.netbeans.modules.cnd.api.model.CsmProject; +import org.netbeans.modules.cnd.api.model.CsmVariable; import org.netbeans.modules.cnd.api.model.util.CsmKindUtilities; import org.netbeans.modules.cnd.api.model.xref.CsmReference; import org.netbeans.modules.cnd.api.model.xref.CsmReferenceResolver; @@ -75,7 +77,7 @@ if (activatedNodes == null || activatedNodes.length == 0) { return null; } - CsmFunction function = null; + CsmOffsetableDeclaration declaration = null; CsmProject project = null; CsmReference ref = CsmReferenceResolver.getDefault().findReference(activatedNodes[0]); if (ref == null) { @@ -91,15 +93,17 @@ } CsmObject obj = ref.getReferencedObject(); if (CsmKindUtilities.isFunction(obj)) { - function = (CsmFunction) obj; + declaration = (CsmFunction) obj; + } else if(CsmKindUtilities.isVariable(obj)) { + declaration = (CsmVariable) obj; } else { obj = ref.getClosestTopLevelObject(); if (CsmKindUtilities.isFunction(obj)) { - function = (CsmFunction) obj; + declaration = (CsmFunction) obj; } } - if (function != null) { - return new CallModelImpl(project, function); + if (declaration != null) { + return new CallModelImpl(project, declaration); } return null; } diff --git a/cnd.navigation/src/org/netbeans/modules/cnd/navigation/callgraph/CallImpl.java b/cnd.navigation/src/org/netbeans/modules/cnd/navigation/callgraph/CallImpl.java --- a/cnd.navigation/src/org/netbeans/modules/cnd/navigation/callgraph/CallImpl.java +++ b/cnd.navigation/src/org/netbeans/modules/cnd/navigation/callgraph/CallImpl.java @@ -44,6 +44,9 @@ import org.netbeans.modules.cnd.api.model.CsmFunction; import org.netbeans.modules.cnd.api.model.CsmModelAccessor; +import org.netbeans.modules.cnd.api.model.CsmOffsetableDeclaration; +import org.netbeans.modules.cnd.api.model.CsmVariable; +import org.netbeans.modules.cnd.api.model.util.CsmKindUtilities; import org.netbeans.modules.cnd.api.model.xref.CsmReference; import org.netbeans.modules.cnd.api.model.xref.CsmReferenceSupport; import org.netbeans.modules.cnd.callgraph.api.Call; @@ -55,32 +58,31 @@ * @author Alexander Simon */ public class CallImpl implements Call { - + private final Function owner; + private final Function callee; + private final boolean nameOrder; private final CsmReference reference; - private final Function function; - private final boolean nameOrder; - private final CharSequence name; - private final CharSequence display; + private final CharSequence description; + private final CharSequence htmlName; - public CallImpl(CsmFunction owner, CsmReference reference, CsmFunction function, boolean nameOrder){ - this.owner = new FunctionImpl(owner); + public CallImpl(CsmOffsetableDeclaration owner, CsmReference reference, CsmOffsetableDeclaration callee, boolean nameOrder) { + this.nameOrder = nameOrder; + this.owner = implementationResolver(owner); + this.callee = implementationResolver(callee); this.reference = reference; - this.function = new FunctionImpl(function); - this.nameOrder = nameOrder; - name = initDescription(); - display = initHtmlDisplayName(); + this.description = initDescription(); + this.htmlName = initHtmlDisplayName(); } - + public Object getReferencedCall() { return reference; } - + @Override public void open() { final String taskName = "Open function call"; //NOI18N Runnable run = new Runnable() { - @Override public void run() { CsmUtilities.openSource(reference); @@ -88,29 +90,33 @@ }; CsmModelAccessor.getModel().enqueue(run, taskName); } - + @Override public Function getCallee() { - return function; + return callee; } @Override public Function getCaller() { return owner; } + + @Override + public String getHtmlDisplayName() { + if (htmlName != null) { + return htmlName.toString(); + } + return null; + } @Override - public int compareTo(Call o) { - if (nameOrder) { - return getCaller().getName().compareTo(o.getCaller().getName()); + public String getDescription() { + if (description != null) { + return description.toString(); } - int diff = reference.getStartOffset() - ((CallImpl)o).reference.getStartOffset(); - if (diff == 0) { - return getCallee().getName().compareTo(o.getCallee().getName()); - } - return diff; + return null; } - + @Override public String toString() { if (nameOrder) { @@ -119,23 +125,19 @@ return getCaller().getName()+"->"+getCallee().getName(); // NOI18N } } - + @Override - public String getHtmlDisplayName() { - if (display != null) { - return display.toString(); + public int compareTo(Call o) { + if (nameOrder) { + return getCaller().getName().compareTo(o.getCaller().getName()); } - return null; + int diff = reference.getStartOffset() - ((CallImpl)o).reference.getStartOffset(); + if (diff == 0) { + return getCallee().getName().compareTo(o.getCallee().getName()); + } + return diff; } - - @Override - public String getDescription() { - if (name != null) { - return name.toString(); - } - return null; - } - + private CharSequence initHtmlDisplayName() { return CsmReferenceSupport.getContextLineHtml(reference, true); } @@ -143,4 +145,15 @@ private CharSequence initDescription() { return CsmReferenceSupport.getContextLine(reference); } + + private static Function implementationResolver(CsmOffsetableDeclaration entity) { + if (CsmKindUtilities.isFunction(entity)) { + return new FunctionImpl((CsmFunction) entity); + } else if (CsmKindUtilities.isVariable(entity)) { + return new VariableImpl((CsmVariable) entity); + } else { + return null; + } + } + } diff --git a/cnd.navigation/src/org/netbeans/modules/cnd/navigation/callgraph/CallModelImpl.java b/cnd.navigation/src/org/netbeans/modules/cnd/navigation/callgraph/CallModelImpl.java --- a/cnd.navigation/src/org/netbeans/modules/cnd/navigation/callgraph/CallModelImpl.java +++ b/cnd.navigation/src/org/netbeans/modules/cnd/navigation/callgraph/CallModelImpl.java @@ -62,10 +62,12 @@ import org.netbeans.modules.cnd.api.model.CsmNamespaceDefinition; import org.netbeans.modules.cnd.api.model.CsmObject; import org.netbeans.modules.cnd.api.model.CsmOffsetable; +import org.netbeans.modules.cnd.api.model.CsmOffsetableDeclaration; import org.netbeans.modules.cnd.api.model.CsmProject; import org.netbeans.modules.cnd.api.model.CsmScope; import org.netbeans.modules.cnd.api.model.CsmTypedef; import org.netbeans.modules.cnd.api.model.CsmUID; +import org.netbeans.modules.cnd.api.model.CsmVariable; import org.netbeans.modules.cnd.api.model.services.CsmCacheManager; import org.netbeans.modules.cnd.api.model.services.CsmFileInfoQuery; import org.netbeans.modules.cnd.api.model.services.CsmFileReferences; @@ -89,26 +91,26 @@ */ public class CallModelImpl implements CallModel { private final CsmReferenceRepository repository; - private final CsmFileReferences references; + private final CsmFileReferences fileReferences; private final CsmProject project; private String name; - private FunctionUIN uin; + private DeclarationUIN uin; - public CallModelImpl(CsmProject project, CsmFunction root){ + public CallModelImpl(CsmProject project, CsmOffsetableDeclaration root) { repository = CsmReferenceRepository.getDefault(); - references = CsmFileReferences.getDefault(); + fileReferences = CsmFileReferences.getDefault(); this.project = project; - uin = new FunctionUIN(project, root); + uin = new CallModelImpl.DeclarationUIN(project, root); name = root.getName().toString(); } @Override public Function getRoot() { - CsmFunction root = uin.getFunction(); + CsmOffsetableDeclaration root = uin.getDeclaration(); if (root != null) { CsmCacheManager.enter(); try { - return new FunctionImpl(root); + return implementationResolver(root); } finally { CsmCacheManager.leave(); } @@ -132,9 +134,16 @@ FunctionImpl impl = (FunctionImpl)newRoot; CsmFunction f = impl.getDefinition(); if (f != null) { - uin = new FunctionUIN(project, f); + uin = new DeclarationUIN(project, f); name = f.getName().toString(); } + } else if (newRoot instanceof VariableImpl) { + VariableImpl impl = (VariableImpl)newRoot; + CsmVariable v = impl.getVariable(); + if (v != null) { + uin = new DeclarationUIN(project, v); + name = v.getName().toString(); + } } } @@ -152,23 +161,37 @@ public List getCallers(Function declaration) { CsmCacheManager.enter(); try { - FunctionImpl functionImpl = (FunctionImpl) declaration; - CsmFunction owner = functionImpl.getDeclaration(); - Collection functions = new ArrayList(); - functions.add(owner); - if (CallGraphPreferences.isShowOverriding()) { - if (CsmKindUtilities.isMethodDeclaration(owner)) { - Collection overrides = CsmVirtualInfoQuery.getDefault().getAllBaseDeclarations((CsmMethod) owner); - functions.addAll(overrides); + Collection declarations = new ArrayList(); + List res = new ArrayList(); + + if (declaration instanceof FunctionImpl) { + FunctionImpl functionImpl = (FunctionImpl) declaration; + CsmFunction owner = functionImpl.getDeclaration(); + declarations.add(owner); + if (CallGraphPreferences.isShowOverriding()) { + if (CsmKindUtilities.isMethodDeclaration(owner)) { + Collection overrides = CsmVirtualInfoQuery.getDefault().getAllBaseDeclarations((CsmMethod) owner); + declarations.addAll(overrides); + } } + } else if (declaration instanceof VariableImpl) { + declarations.add(((VariableImpl) declaration).getVariable()); + } else { + return res; } - EnumSet kinds = EnumSet.of(CsmReferenceKind.DIRECT_USAGE, CsmReferenceKind.UNKNOWN); - List res = new ArrayList(); + + EnumSet kinds; + if (declaration instanceof FunctionImpl) { + kinds = EnumSet.of(CsmReferenceKind.DIRECT_USAGE, CsmReferenceKind.UNKNOWN); + } else { + kinds = EnumSet.of(CsmReferenceKind.DIRECT_USAGE, CsmReferenceKind.UNKNOWN, CsmReferenceKind.DECLARATION); + } + HashMap set = new HashMap(); HashMap macros = new HashMap(); - for(CsmFunction function : functions) { - if (CsmKindUtilities.isFunction(function) && function.getContainingFile().isValid()) { - for(CsmReference r : repository.getReferences(function, project, CsmReferenceKind.ANY_REFERENCE_IN_ACTIVE_CODE, Interrupter.DUMMY)){ + for(CsmOffsetableDeclaration decl : declarations) { + if (decl.getContainingFile().isValid()) { + for(CsmReference r : repository.getReferences(decl, project, CsmReferenceKind.ANY_REFERENCE_IN_ACTIVE_CODE, Interrupter.DUMMY)){ if (r == null) { continue; } @@ -203,10 +226,21 @@ } } } - final CsmFunction functionDeclaration = getFunctionDeclaration(owner); - if (functionDeclaration != null) { + + CsmOffsetableDeclaration owner; + if (declaration instanceof FunctionImpl) { + FunctionImpl functionImpl = (FunctionImpl) declaration; + owner = functionImpl.getDeclaration(); + } else if (declaration instanceof VariableImpl) { + owner = ((VariableImpl) declaration).getVariable(); + } else { + owner = null; + } + + final CsmOffsetableDeclaration ownerDeclaration = owner; + if (ownerDeclaration != null) { for(Map.Entry r : set.entrySet()){ - res.add(new CallImpl(r.getKey(), r.getValue(), functionDeclaration, true)); + res.add(new CallImpl(r.getKey(), r.getValue(), ownerDeclaration, true)); } } return res; @@ -224,64 +258,70 @@ public List getCallees(Function definition) { CsmCacheManager.enter(); try { - FunctionImpl definitionImpl = (FunctionImpl) definition; - CsmFunction owner = definitionImpl.getDefinition(); - Collection functions = new ArrayList(); - functions.add(owner); - if (CallGraphPreferences.isShowOverriding()) { - if (CsmKindUtilities.isMethodDeclaration(owner)) { - Collection overrides = CsmVirtualInfoQuery.getDefault().getOverriddenMethods((CsmMethod) owner, false); - functions.addAll(overrides); + if (definition instanceof VariableImpl) { + return new ArrayList(); + } else if (definition instanceof FunctionImpl) { + FunctionImpl definitionImpl = (FunctionImpl) definition; + CsmFunction owner = definitionImpl.getDefinition(); + Collection functions = new ArrayList(); + functions.add(owner); + if (CallGraphPreferences.isShowOverriding()) { + if (CsmKindUtilities.isMethodDeclaration(owner)) { + Collection overrides = CsmVirtualInfoQuery.getDefault().getOverriddenMethods((CsmMethod) owner, false); + functions.addAll(overrides); + } } - } - List res = new ArrayList(); - final HashMap set = new HashMap(); - for(CsmFunction function : functions) { - if (CsmKindUtilities.isFunctionDefinition(function) && function.getContainingFile().isValid()) { - final List list = CsmFileInfoQuery.getDefault().getUnusedCodeBlocks((function).getContainingFile(), Interrupter.DUMMY); - references.accept((CsmScope)function, null, new CsmFileReferences.Visitor() { - @Override - public void visit(CsmReferenceContext context) { - CsmReference r = context.getReference(); - if (r == null) { - return; - } - for(CsmOffsetable offset:list){ - if (offset.getStartOffset()<=r.getStartOffset() && - offset.getEndOffset() >=r.getEndOffset()){ + List res = new ArrayList(); + final HashMap set = new HashMap(); + for(CsmFunction function : functions) { + if (CsmKindUtilities.isFunctionDefinition(function) && function.getContainingFile().isValid()) { + final List list = CsmFileInfoQuery.getDefault().getUnusedCodeBlocks((function).getContainingFile(), Interrupter.DUMMY); + fileReferences.accept((CsmScope)function, null, new CsmFileReferences.Visitor() { + @Override + public void visit(CsmReferenceContext context) { + CsmReference r = context.getReference(); + if (r == null) { return; } - } - try { - CsmObject o = r.getReferencedObject(); - if (CsmKindUtilities.isFunction(o) && - !CsmReferenceResolver.getDefault().isKindOf(r, CsmReferenceKind.FUNCTION_DECLARATION_KINDS)) { - o = getFunctionDeclaration((CsmFunction)o); - if (!set.containsKey((CsmFunction)o)) { - set.put((CsmFunction)o, r); + for(CsmOffsetable offset:list){ + if (offset.getStartOffset()<=r.getStartOffset() && + offset.getEndOffset() >=r.getEndOffset()){ + return; } } - } catch (AssertionError e){ - e.printStackTrace(System.err); - } catch (Exception e) { - e.printStackTrace(System.err); + try { + CsmObject o = r.getReferencedObject(); + if (CsmKindUtilities.isFunction(o) && + !CsmReferenceResolver.getDefault().isKindOf(r, CsmReferenceKind.FUNCTION_DECLARATION_KINDS)) { + o = getFunctionDeclaration((CsmFunction)o); + if (!set.containsKey((CsmFunction)o)) { + set.put((CsmFunction)o, r); + } + } + } catch (AssertionError e){ + e.printStackTrace(System.err); + } catch (Exception e) { + e.printStackTrace(System.err); + } } - } - @Override - public boolean cancelled() { - return false; - } - }, CsmReferenceKind.ANY_REFERENCE_IN_ACTIVE_CODE); + @Override + public boolean cancelled() { + return false; + } + }, CsmReferenceKind.ANY_REFERENCE_IN_ACTIVE_CODE); + } } + final CsmFunction functionDeclaration = getFunctionDeclaration(owner); + if (functionDeclaration != null) { + for(Map.Entry r : set.entrySet()){ + res.add(new CallImpl(functionDeclaration, r.getValue(),r.getKey(), false)); + } + } + return res; + } else { + return new ArrayList(); } - final CsmFunction functionDeclaration = getFunctionDeclaration(owner); - if (functionDeclaration != null) { - for(Map.Entry r : set.entrySet()){ - res.add(new CallImpl( functionDeclaration, r.getValue(),r.getKey(), false)); - } - } - return res; } finally { CsmCacheManager.leave(); } @@ -312,23 +352,22 @@ return null; } - private static class FunctionUIN { - + private static class DeclarationUIN { private final CsmProject project; - private final CharSequence functionUin; + private final CharSequence declarationUin; private final CsmUID fileUid; - - private FunctionUIN(CsmProject project, CsmFunction root) { + + private DeclarationUIN(CsmProject project, CsmOffsetableDeclaration declaration) { this.project = project; - functionUin = root.getUniqueName(); - fileUid = UIDs.get(root.getContainingFile()); + fileUid = UIDs.get(declaration.getContainingFile()); + declarationUin = declaration.getUniqueName(); } - - private CsmFunction getFunction() { + + private CsmOffsetableDeclaration getDeclaration() { if (!project.isValid()) { return null; } - CsmFunction root = (CsmFunction) project.findDeclaration(functionUin); + CsmOffsetableDeclaration root = (CsmOffsetableDeclaration) project.findDeclaration(declarationUin); if (root != null) { return root; } @@ -337,24 +376,24 @@ return null; } for (CsmDeclaration d : file.getDeclarations()) { - root = findFunction(d); + root = findDeclaration(d); if (root != null){ return root; } } return null; } - - private CsmFunction findFunction(CsmDeclaration element) { + + private CsmOffsetableDeclaration findDeclaration(CsmDeclaration element) { if (CsmKindUtilities.isTypedef(element) || CsmKindUtilities.isTypeAlias(element)) { CsmTypedef def = (CsmTypedef) element; if (def.isTypeUnnamed()) { CsmClassifier cls = def.getType().getClassifier(); if (cls != null && cls.getName().length() == 0 && (cls instanceof CsmCompoundClassifier)) { - return findFunction((CsmCompoundClassifier) cls); + return findDeclaration((CsmCompoundClassifier) cls); } - } + } return null; } else if (CsmKindUtilities.isClassifier(element)) { String name = ((CsmClassifier) element).getName().toString(); @@ -366,14 +405,14 @@ } if (CsmKindUtilities.isClass(element)) { CsmClass cls = (CsmClass) element; - for (CsmMember m : cls.getMembers()) { - CsmFunction res = findFunction(m); + for (CsmMember member : cls.getMembers()) { + CsmOffsetableDeclaration res = findDeclaration(member); if (res != null) { return res; } } - for (CsmFriend m : cls.getFriends()) { - CsmFunction res = findFunction(m); + for (CsmFriend friend : cls.getFriends()) { + CsmOffsetableDeclaration res = findDeclaration(friend); if (res != null) { return res; } @@ -382,17 +421,56 @@ return null; } else if (CsmKindUtilities.isNamespaceDefinition(element)) { for (CsmDeclaration d : ((CsmNamespaceDefinition) element).getDeclarations()) { - CsmFunction res = findFunction(d); + CsmOffsetableDeclaration res = findDeclaration(d); if (res != null) { return res; } } - } else if (CsmKindUtilities.isFunction(element)) { - if (element.getUniqueName().equals(functionUin)) { - return (CsmFunction) element; + } else if (CsmKindUtilities.isOffsetableDeclaration(element)) { + final ArrayList list = new ArrayList(); + CsmFileReferences fr = CsmFileReferences.getDefault(); + fr.accept((CsmScope)element.getScope(), null, new CsmFileReferences.Visitor() { + @Override + public void visit(CsmReferenceContext context) { + CsmReference r = context.getReference(); + if (r == null) { + return; + } + try { + CsmObject obj = r.getReferencedObject(); + if (CsmKindUtilities.isVariable(obj)) { + CsmVariable var = (CsmVariable) obj; + if (var.getUniqueName().equals(declarationUin)) { + list.add(var); + } + } + } catch (AssertionError e){ + e.printStackTrace(System.err); + } catch (Exception e) { + e.printStackTrace(System.err); + } + } + + @Override + public boolean cancelled() { + return false; + } + }, CsmReferenceKind.ANY_REFERENCE_IN_ACTIVE_CODE); + if (!list.isEmpty()) { + return (CsmOffsetableDeclaration) list.get(0); } } return null; } } + + private static Function implementationResolver(CsmOffsetableDeclaration entity) { + if (CsmKindUtilities.isFunction(entity)) { + return new FunctionImpl((CsmFunction) entity); + } else if (CsmKindUtilities.isVariable(entity)) { + return new VariableImpl((CsmVariable) entity); + } else { + return null; + } + } } diff --git a/cnd.navigation/src/org/netbeans/modules/cnd/navigation/callgraph/FunctionImpl.java b/cnd.navigation/src/org/netbeans/modules/cnd/navigation/callgraph/FunctionImpl.java --- a/cnd.navigation/src/org/netbeans/modules/cnd/navigation/callgraph/FunctionImpl.java +++ b/cnd.navigation/src/org/netbeans/modules/cnd/navigation/callgraph/FunctionImpl.java @@ -257,4 +257,9 @@ public String toString() { return getName(); } + + @Override + public boolean isFunction() { + return true; + } } diff --git a/cnd.navigation/src/org/netbeans/modules/cnd/navigation/callgraph/VariableImpl.java b/cnd.navigation/src/org/netbeans/modules/cnd/navigation/callgraph/VariableImpl.java new file mode 100644 --- /dev/null +++ b/cnd.navigation/src/org/netbeans/modules/cnd/navigation/callgraph/VariableImpl.java @@ -0,0 +1,198 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2015 Sun Microsystems, Inc. + */ +package org.netbeans.modules.cnd.navigation.callgraph; + +import java.awt.Image; +import java.util.HashMap; +import java.util.Map; +import org.netbeans.modules.cnd.api.model.CsmVariable; +import org.netbeans.modules.cnd.api.model.CsmClass; +import org.netbeans.modules.cnd.api.model.CsmDeclaration; +import org.netbeans.modules.cnd.api.model.CsmField; +import org.netbeans.modules.cnd.api.model.CsmModelAccessor; +import org.netbeans.modules.cnd.api.model.util.CsmKindUtilities; +import org.netbeans.modules.cnd.callgraph.api.Function; +import org.netbeans.modules.cnd.modelutil.CsmDisplayUtilities; +import org.netbeans.modules.cnd.modelutil.CsmImageLoader; +import org.netbeans.modules.cnd.modelutil.CsmUtilities; +import org.openide.util.NbBundle; + +/** + * + * @author toor + */ +public class VariableImpl implements Function { + private static final Map preferredIcons = new HashMap(); + + static { + preferredIcons.put(CsmDeclaration.Kind.VARIABLE, CsmDeclaration.Kind.VARIABLE_DEFINITION); + } + + private final CsmVariable variable; + private String htmlDisplayName = ""; // NOI18N + private String scopeName = null; // NOI18N + + public VariableImpl(CsmVariable variable) { + this.variable = variable; + } + + @Override + public String getName() { + return variable.getName().toString(); + } + + @Override + public String getScopeName() { + if (scopeName == null) { + scopeName = ""; + try { + if (CsmKindUtilities.isField(variable)) { + CsmClass cls = ((CsmField) variable).getContainingClass(); + if (cls != null && cls.getName().length() > 0) { + scopeName = cls.getName().toString()+"::"; // NOI18N + } + } + } catch (AssertionError ex) { + ex.printStackTrace(System.err); + } catch (Exception ex) { + ex.printStackTrace(System.err); + } + } + return scopeName; + } + + public CsmVariable getVariable() { + return variable; + } + + @Override + public String getHtmlDisplayName() { + if (htmlDisplayName.length() == 0) { + htmlDisplayName = createHtmlDisplayName(); + } + return htmlDisplayName; + } + + private String createHtmlDisplayName() { + String displayName = variable.getName().toString(); + + try { + if (CsmKindUtilities.isField(variable)) { + CsmClass cls = ((CsmField) variable).getContainingClass(); + if (cls != null && cls.getName().length() > 0) { + String name = CsmDisplayUtilities.htmlize(cls.getName().toString()); + String in = NbBundle.getMessage(CallImpl.class, "LBL_inClass"); // NOI18N + return displayName + " " + in + " " + name; // NOI18N + } + } + } catch (AssertionError ex) { + ex.printStackTrace(System.err); + } catch (Exception ex) { + ex.printStackTrace(System.err); + } + + return displayName; + } + + @Override + public String getDescription() { + return getScopeName()+getName(); + } + + @Override + public Image getIcon() { + try { + return CsmImageLoader.getImage(variable, preferredIcons); + } catch (AssertionError ex) { + ex.printStackTrace(System.err); + } catch (Exception ex) { + ex.printStackTrace(System.err); + } + return null; + } + + @Override + public void open() { + final String taskName = "Open declaration"; //NOI18N + Runnable run = new Runnable() { + + @Override + public void run() { + CsmUtilities.openSource(variable); + } + }; + CsmModelAccessor.getModel().enqueue(run, taskName); + } + + @Override + public boolean equals(Object obj) { + if (variable != null) { + if (obj instanceof VariableImpl) { + return variable.equals(((VariableImpl) obj).getVariable()); + } + } + return super.equals(obj); + } + + @Override + public int hashCode() { + if (variable != null) { + return variable.hashCode(); + } + return super.hashCode(); + } + + @Override + public String toString() { + return getName(); + } + + @Override + public boolean isVurtual() { + return false; + } + + @Override + public boolean isFunction() { + return false; + } +}