Java tutorial
/* * CPAchecker is a tool for configurable software verification. * This file is part of CPAchecker. * * Copyright (C) 2007-2014 Dirk Beyer * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * CPAchecker web page: * http://cpachecker.sosy-lab.org */ package org.sosy_lab.cpachecker.cpa.arg; import static org.sosy_lab.cpachecker.util.automaton.AutomatonGraphmlCommon.SINK_NODE_ID; import java.io.IOException; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.Deque; import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import javax.annotation.Nullable; import javax.xml.parsers.ParserConfigurationException; import org.sosy_lab.common.Pair; import org.sosy_lab.common.configuration.Configuration; import org.sosy_lab.common.configuration.InvalidConfigurationException; import org.sosy_lab.common.configuration.Option; import org.sosy_lab.common.configuration.Options; import org.sosy_lab.cpachecker.cfa.ast.FileLocation; import org.sosy_lab.cpachecker.cfa.ast.ALeftHandSide; import org.sosy_lab.cpachecker.cfa.ast.AAssignment; import org.sosy_lab.cpachecker.cfa.ast.c.CArraySubscriptExpression; import org.sosy_lab.cpachecker.cfa.ast.c.CBinaryExpression; import org.sosy_lab.cpachecker.cfa.ast.c.CCastExpression; import org.sosy_lab.cpachecker.cfa.ast.c.CCharLiteralExpression; import org.sosy_lab.cpachecker.cfa.ast.c.CComplexCastExpression; import org.sosy_lab.cpachecker.cfa.ast.c.CExpressionVisitor; import org.sosy_lab.cpachecker.cfa.ast.c.CFieldReference; import org.sosy_lab.cpachecker.cfa.ast.c.CFloatLiteralExpression; import org.sosy_lab.cpachecker.cfa.ast.c.CIdExpression; import org.sosy_lab.cpachecker.cfa.ast.c.CImaginaryLiteralExpression; import org.sosy_lab.cpachecker.cfa.ast.c.CIntegerLiteralExpression; import org.sosy_lab.cpachecker.cfa.ast.c.CLeftHandSide; import org.sosy_lab.cpachecker.cfa.ast.c.CParameterDeclaration; import org.sosy_lab.cpachecker.cfa.ast.c.CPointerExpression; import org.sosy_lab.cpachecker.cfa.ast.c.CSimpleDeclaration; import org.sosy_lab.cpachecker.cfa.ast.c.CStringLiteralExpression; import org.sosy_lab.cpachecker.cfa.ast.c.CTypeIdExpression; import org.sosy_lab.cpachecker.cfa.ast.c.CUnaryExpression; import org.sosy_lab.cpachecker.cfa.model.AssumeEdge; import org.sosy_lab.cpachecker.cfa.model.CFAEdge; import org.sosy_lab.cpachecker.cfa.model.CFANode; import org.sosy_lab.cpachecker.cfa.model.FunctionCallEdge; import org.sosy_lab.cpachecker.cfa.model.FunctionEntryNode; import org.sosy_lab.cpachecker.cfa.model.FunctionExitNode; import org.sosy_lab.cpachecker.cfa.model.MultiEdge; import org.sosy_lab.cpachecker.core.CounterexampleInfo; import org.sosy_lab.cpachecker.core.counterexample.CFAEdgeWithAssignments; import org.sosy_lab.cpachecker.core.counterexample.CFAPathWithAssignments; import org.sosy_lab.cpachecker.core.counterexample.Model; import org.sosy_lab.cpachecker.util.AbstractStates; import org.sosy_lab.cpachecker.util.CFAUtils; import org.sosy_lab.cpachecker.util.SourceLocationMapper; import org.sosy_lab.cpachecker.util.automaton.AutomatonGraphmlCommon; import org.sosy_lab.cpachecker.util.automaton.AutomatonGraphmlCommon.GraphMlBuilder; import org.sosy_lab.cpachecker.util.automaton.AutomatonGraphmlCommon.GraphType; import org.sosy_lab.cpachecker.util.automaton.AutomatonGraphmlCommon.KeyDef; import org.sosy_lab.cpachecker.util.automaton.AutomatonGraphmlCommon.NodeFlag; import org.sosy_lab.cpachecker.util.automaton.AutomatonGraphmlCommon.NodeType; import org.w3c.dom.Element; import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.base.Strings; import com.google.common.collect.FluentIterable; import com.google.common.collect.HashMultimap; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.Queues; import com.google.common.collect.Range; import com.google.common.collect.RangeSet; import com.google.common.collect.Sets; import com.google.common.collect.TreeRangeSet; @Options(prefix = "cpa.arg.witness") public class ARGPathExport { @Option(secure = true, description = "Verification witness: Include function calls and function returns?") boolean exportFunctionCallsAndReturns = true; @Option(secure = true, description = "Verification witness: Include assumptions (C statements)?") boolean exportAssumptions = true; @Option(secure = true, description = "Verification witness: Include the considered case of an assume?") boolean exportAssumeCaseInfo = true; @Option(secure = true, description = "Verification witness: Include the token numbers of the operations on the transitions?") boolean exportTokenNumbers = true; @Option(secure = true, description = "Verification witness: Include the (starting) line numbers of the operations on the transitions?") boolean exportLineNumbers = true; @Option(secure = true, description = "Verification witness: Include the sourcecode of the operations?") boolean exportSourcecode = true; public ARGPathExport(Configuration config) throws InvalidConfigurationException { Preconditions.checkNotNull(config); config.inject(this); } private String tokensToText(Set<Integer> tokens) { StringBuilder result = new StringBuilder(); RangeSet<Integer> tokenRanges = TreeRangeSet.create(); for (Integer token : tokens) { tokenRanges.add(Range.closed(token, token)); } for (Range<Integer> range : tokenRanges.asRanges()) { if (result.length() > 0) { result.append(","); } Integer from = range.lowerEndpoint(); Integer to = range.upperEndpoint(); if (to - from == 0) { result.append(from); } else { result.append(from); result.append("-"); result.append(to); } } return result.toString(); } private String getStateIdent(ARGState state) { return getStateIdent(state, ""); } private String getStateIdent(ARGState state, String identPostfix) { return String.format("A%d%s", state.getStateId(), identPostfix); } private String getPseudoStateIdent(ARGState state, int subStateNo, int subStateCount) { return getStateIdent(state, String.format("_%d_%d", subStateNo, subStateCount)); } private static class TransitionCondition { public final Map<KeyDef, String> keyValues = Maps.newHashMap(); public void put(final KeyDef key, final String value) { keyValues.put(key, value); } @Override public boolean equals(Object o) { if (!(o instanceof TransitionCondition)) { return false; } TransitionCondition oT = (TransitionCondition) o; return this.keyValues.equals(oT.keyValues); } public boolean hasTransitionRestrictions() { return !keyValues.isEmpty(); } @Override public int hashCode() { return keyValues.hashCode(); } } private static class AggregatedEdge { public final String source; public final String targetRepresentedBy; public final TransitionCondition condition; public final Set<String> aggregatesTargets = Sets.newHashSet(); public AggregatedEdge(final String source, final String targetRepresentedBy, final TransitionCondition condition) { this.source = source; this.condition = condition; this.targetRepresentedBy = targetRepresentedBy; this.aggregatesTargets.add(targetRepresentedBy); } } public void writePath(Appendable sb, final ARGState rootState, final Function<? super ARGState, ? extends Iterable<ARGState>> successorFunction, final Predicate<? super ARGState> displayedElements, final Predicate<? super Pair<ARGState, ARGState>> pathEdges, CounterexampleInfo pCounterExample) throws IOException { String defaultFileName = getInitialFileName(rootState); WitnessWriter writer = new WitnessWriter(defaultFileName); writer.writePath(sb, rootState, successorFunction, displayedElements, pathEdges, pCounterExample); } private String getInitialFileName(ARGState s) { CFANode initialLoc = AbstractStates.extractLocation(s); Deque<CFANode> worklist = Queues.newArrayDeque(); worklist.push(initialLoc); while (!worklist.isEmpty()) { CFANode l = worklist.pop(); for (CFAEdge e : CFAUtils.leavingEdges(l)) { Set<FileLocation> fileLocations = SourceLocationMapper.getFileLocationsFromCfaEdge(e); if (fileLocations.size() > 0) { String fileName = fileLocations.iterator().next().getFileName(); if (fileName != null) { return fileName; } } worklist.push(e.getSuccessor()); } } throw new RuntimeException("Could not determine file name based on abstract state!"); } private class WitnessWriter { private final Multimap<String, AggregatedEdge> sourceToTargetMap = HashMultimap.create(); private final Multimap<String, AggregatedEdge> targetToSourceMap = HashMultimap.create(); private final Map<String, Element> delayedNodes = Maps.newHashMap(); private final Map<DelayedAssignmentsKey, CFAEdgeWithAssignments> delayedAssignments = Maps.newHashMap(); private final String defaultSourcefileName; public WitnessWriter(@Nullable String defaultSourcefileName) { this.defaultSourcefileName = defaultSourcefileName; } @SuppressWarnings("unused") private boolean isNodeRepresentingOneOf(Collection<AggregatedEdge> targets, String nodeId) { for (AggregatedEdge t : targets) { if (t.targetRepresentedBy.equals(nodeId)) { return true; } } return false; } private boolean containsRestrictedEdgeTo(Collection<AggregatedEdge> targets, String nodeId) { for (AggregatedEdge t : targets) { if (t.targetRepresentedBy.equals(nodeId)) { if (t.condition.hasTransitionRestrictions()) { return true; } } } return false; } private void appendNewPathNode(GraphMlBuilder doc, String nodeId, EnumSet<NodeFlag> nodeFlags) throws IOException { Element result = doc.createNodeElement(nodeId, NodeType.ONPATH); for (NodeFlag f : nodeFlags) { doc.addDataElementChild(result, f.key, "true"); } // Decide if writing the node should be delayed. // Some nodes might not get referenced by edges later. Collection<AggregatedEdge> existingEdgesTo = targetToSourceMap.get(nodeId); // -- A node must always be written if it represents a set of aggregated nodes if (containsRestrictedEdgeTo(existingEdgesTo, nodeId)) { doc.appendToAppendable(result); } else { delayedNodes.put(nodeId, result); } } private void appendDelayedNode(final GraphMlBuilder doc, final String nodeId) { Element e = delayedNodes.get(nodeId); if (e != null) { delayedNodes.remove(nodeId); doc.appendToAppendable(e); } } private void appendNewEdge(final GraphMlBuilder doc, String from, final String to, final CFAEdge edge, final ARGState fromState, final Map<ARGState, CFAEdgeWithAssignments> valueMap) throws IOException { TransitionCondition desc = constructTransitionCondition(from, to, edge, fromState, valueMap); if (aggregateToPrevEdge(from, to, desc)) { return; } // Switch the source node (from) to the aggregating one // -- only if this is unambiguous Collection<AggregatedEdge> edgesToTheSourceNode = targetToSourceMap.get(from); if (edgesToTheSourceNode.size() == 1) { AggregatedEdge aggregationEdge = edgesToTheSourceNode.iterator().next(); from = aggregationEdge.targetRepresentedBy; // If there is a edge to "from" with an empty transition condition (epsilon) // then switch "from" to the "from" of the epsilon edge if (!aggregationEdge.condition.hasTransitionRestrictions()) { from = aggregationEdge.source; } // -- delay writing epsilon edges! } if (desc.hasTransitionRestrictions()) { appendDelayedNode(doc, from); appendDelayedNode(doc, to); Element result = doc.createEdgeElement(from, to); for (KeyDef k : desc.keyValues.keySet()) { doc.addDataElementChild(result, k, desc.keyValues.get(k)); } doc.appendToAppendable(result); } AggregatedEdge t = new AggregatedEdge(from, to, desc); sourceToTargetMap.put(from, t); targetToSourceMap.put(to, t); } private boolean aggregateToPrevEdge(String from, final String to, TransitionCondition desc) { // What edges to "from" exist? // edgesTo(from) = [e | e = (u,c,v) in E, v = from] Collection<AggregatedEdge> edgesToTheSourceNode = targetToSourceMap.get(from); if (edgesToTheSourceNode.size() == 1) { AggregatedEdge aggregationEdge = edgesToTheSourceNode.iterator().next(); // Does the transition descriptor of TT match (equals) the descriptor of this transition? // edgesTo(from)[1].c == this.c if (aggregationEdge.condition.equals(desc)) { // If everything can be answered with "yes": // Instead of adding a new transition, modify the points-to information of TT aggregationEdge.aggregatesTargets.add(to); targetToSourceMap.put(to, aggregationEdge); return true; } } return false; } private TransitionCondition constructTransitionCondition(String from, String to, final CFAEdge edge, ARGState fromState, Map<ARGState, CFAEdgeWithAssignments> valueMap) { TransitionCondition desc = new TransitionCondition(); //desc.put(KeyDef.CFAPREDECESSORNODE, edge.getPredecessor().toString()); //desc.put(KeyDef.CFASUCCESSORNODE, edge.getSuccessor().toString()); if (exportFunctionCallsAndReturns) { if (edge.getSuccessor() instanceof FunctionEntryNode) { FunctionEntryNode in = (FunctionEntryNode) edge.getSuccessor(); desc.put(KeyDef.FUNCTIONENTRY, in.getFunctionName()); } else if (edge.getSuccessor() instanceof FunctionExitNode) { FunctionExitNode out = (FunctionExitNode) edge.getSuccessor(); desc.put(KeyDef.FUNCTIONEXIT, out.getFunctionName()); } } if (exportAssumptions) { if (fromState != null) { DelayedAssignmentsKey key = new DelayedAssignmentsKey(from, edge, fromState); CFAEdgeWithAssignments cfaEdgeWithAssignments = delayedAssignments.get(key); if (valueMap != null && valueMap.containsKey(fromState)) { CFAEdgeWithAssignments currentEdgeWithAssignments = valueMap.get(fromState); if (cfaEdgeWithAssignments == null) { cfaEdgeWithAssignments = currentEdgeWithAssignments; } else { List<AAssignment> delayedAssignments = cfaEdgeWithAssignments.getAssignments(); List<AAssignment> currentAssignments = currentEdgeWithAssignments.getAssignments(); List<AAssignment> allAssignments = new ArrayList<>( delayedAssignments.size() + currentAssignments.size()); allAssignments.addAll(delayedAssignments); allAssignments.addAll(currentAssignments); cfaEdgeWithAssignments = new CFAEdgeWithAssignments(edge, allAssignments, currentEdgeWithAssignments.getComment()); } } if (cfaEdgeWithAssignments != null) { List<AAssignment> assignments = cfaEdgeWithAssignments.getAssignments(); Predicate<AAssignment> assignsParameterOfOtherFunction = new AssignsParameterOfOtherFunction( edge); List<AAssignment> functionValidAssignments = FluentIterable.from(assignments) .filter(assignsParameterOfOtherFunction).toList(); if (functionValidAssignments.size() < assignments.size()) { cfaEdgeWithAssignments = new CFAEdgeWithAssignments(edge, functionValidAssignments, cfaEdgeWithAssignments.getComment()); FluentIterable<CFAEdge> nextEdges = CFAUtils.leavingEdges(edge.getSuccessor()); if (nextEdges.size() == 1 && fromState.getChildren().size() == 1) { String keyFrom = to; CFAEdge keyEdge = Iterables.getOnlyElement(nextEdges); ARGState keyState = Iterables.getOnlyElement(fromState.getChildren()); List<AAssignment> valueAssignments = FluentIterable.from(assignments) .filter(Predicates.not(assignsParameterOfOtherFunction)).toList(); CFAEdgeWithAssignments valueCFAEdgeWithAssignments = new CFAEdgeWithAssignments( keyEdge, valueAssignments, ""); delayedAssignments.put(new DelayedAssignmentsKey(keyFrom, keyEdge, keyState), valueCFAEdgeWithAssignments); } } String code = cfaEdgeWithAssignments.getAsCode(); if (code != null) { desc.put(KeyDef.ASSUMPTION, code); } } } } if (!AutomatonGraphmlCommon.handleAsEpsilonEdge(edge)) { if (exportAssumeCaseInfo) { if (edge instanceof AssumeEdge) { AssumeEdge a = (AssumeEdge) edge; if (!a.getTruthAssumption()) { desc.put(KeyDef.TOKENSNEGATED, "true"); } } } if (exportTokenNumbers) { Set<Integer> absoluteTokens = SourceLocationMapper.getAbsoluteTokensFromCFAEdge(edge, false); desc.put(KeyDef.TOKENS, tokensToText(absoluteTokens)); } if (exportLineNumbers) { Set<FileLocation> locations = SourceLocationMapper.getFileLocationsFromCfaEdge(edge); if (locations.size() > 0) { FileLocation l = locations.iterator().next(); if (!l.getFileName().equals(defaultSourcefileName)) { desc.put(KeyDef.ORIGINFILE, l.getFileName()); } desc.put(KeyDef.ORIGINLINE, Integer.toString(l.getStartingLineInOrigin())); } } if (exportSourcecode) { desc.put(KeyDef.SOURCECODE, edge.getRawStatement()); } } return desc; } private void appendKeyDefinitions(GraphMlBuilder doc, GraphType graphType) { if (graphType == GraphType.CONDITION) { doc.appendNewKeyDef(KeyDef.INVARIANT, null); doc.appendNewKeyDef(KeyDef.NAMED, null); } doc.appendNewKeyDef(KeyDef.ASSUMPTION, null); doc.appendNewKeyDef(KeyDef.SOURCECODE, null); doc.appendNewKeyDef(KeyDef.SOURCECODELANGUAGE, null); doc.appendNewKeyDef(KeyDef.TOKENS, null); doc.appendNewKeyDef(KeyDef.ORIGINTOKENS, null); doc.appendNewKeyDef(KeyDef.TOKENSNEGATED, "false"); doc.appendNewKeyDef(KeyDef.ORIGINLINE, null); doc.appendNewKeyDef(KeyDef.ORIGINFILE, defaultSourcefileName); doc.appendNewKeyDef(KeyDef.NODETYPE, AutomatonGraphmlCommon.defaultNodeType.text); for (NodeFlag f : NodeFlag.values()) { doc.appendNewKeyDef(f.key, "false"); } doc.appendNewKeyDef(KeyDef.FUNCTIONENTRY, null); doc.appendNewKeyDef(KeyDef.FUNCTIONEXIT, null); } public void writePath(Appendable sb, final ARGState rootState, final Function<? super ARGState, ? extends Iterable<ARGState>> successorFunction, final Predicate<? super ARGState> displayedElements, final Predicate<? super Pair<ARGState, ARGState>> pathEdges, CounterexampleInfo pCounterExample) throws IOException { Map<ARGState, CFAEdgeWithAssignments> valueMap = null; if (pCounterExample != null) { Model model = pCounterExample.getTargetPathModel(); CFAPathWithAssignments cfaPath = model.getCFAPathWithAssignments(); if (cfaPath != null) { ARGPath targetPath = pCounterExample.getTargetPath(); valueMap = model.getExactVariableValues(targetPath); } } Set<ARGState> processed = new HashSet<>(); Deque<ARGState> worklist = new ArrayDeque<>(); worklist.add(rootState); GraphType graphType = GraphType.PROGRAMPATH; GraphMlBuilder doc; try { doc = new GraphMlBuilder(sb); } catch (ParserConfigurationException e) { throw new IOException(e); } // TODO: Full schema details // Version of format.. // TODO! (we could use the version of a XML schema) // ... String entryStateNodeId = getStateIdent(rootState); boolean sinkNodeWritten = false; int multiEdgeCount = 0; // see below doc.appendDocHeader(); appendKeyDefinitions(doc, graphType); doc.appendGraphHeader(graphType, "C"); while (!worklist.isEmpty()) { ARGState s = worklist.removeLast(); if (!displayedElements.apply(s)) { continue; } if (!processed.add(s)) { continue; } // Location of the state CFANode loc = AbstractStates.extractLocation(s); // Write the state String sourceStateNodeId = getStateIdent(s); EnumSet<NodeFlag> sourceNodeFlags = EnumSet.noneOf(NodeFlag.class); if (sourceStateNodeId.equals(entryStateNodeId)) { sourceNodeFlags = EnumSet.of(NodeFlag.ISENTRY); } if (s.isTarget()) { sourceNodeFlags.add(NodeFlag.ISVIOLATION); } appendNewPathNode(doc, sourceStateNodeId, sourceNodeFlags); // Process child states for (ARGState child : successorFunction.apply(s)) { // The child might be covered by another state // --> switch to the covering state if (child.isCovered()) { child = child.getCoveringState(); assert !child.isCovered(); } String childStateId = getStateIdent(child); CFANode childLoc = AbstractStates.extractLocation(child); CFAEdge edgeToNextState = loc.getEdgeTo(childLoc); String prevStateId = sourceStateNodeId; if (edgeToNextState instanceof MultiEdge) { // The successor state might have several incoming MultiEdges. // In this case the state names like ARG<successor>_0 would occur // several times. // So we add this counter to the state names to make them unique. multiEdgeCount++; // Write out a long linear chain of pseudo-states (one state encodes multiple edges) // because the AutomatonCPA also iterates through the MultiEdge. List<CFAEdge> edges = ((MultiEdge) edgeToNextState).getEdges(); // inner part (without last edge) for (int i = 0; i < edges.size() - 1; i++) { CFAEdge innerEdge = edges.get(i); String pseudoStateId = getPseudoStateIdent(child, i, multiEdgeCount); assert (!(innerEdge instanceof AssumeEdge)); appendNewPathNode(doc, pseudoStateId, EnumSet.noneOf(NodeFlag.class)); appendNewEdge(doc, prevStateId, pseudoStateId, innerEdge, null, valueMap); prevStateId = pseudoStateId; } // last edge connecting it with the real successor edgeToNextState = edges.get(edges.size() - 1); } // Only proceed with this state if the path states contains the child boolean isEdgeOnPath = pathEdges.apply(Pair.of(s, child)); if (s.getChildren().contains(child)) { if (isEdgeOnPath) { // Child belongs to the path! appendNewEdge(doc, prevStateId, childStateId, edgeToNextState, s, valueMap); worklist.add(child); } else { // Child does not belong to the path --> add a branch to the SINK node! if (!sinkNodeWritten) { sinkNodeWritten = true; EnumSet<NodeFlag> nodeFlags = EnumSet.of(NodeFlag.ISSINKNODE); appendNewPathNode(doc, SINK_NODE_ID, nodeFlags); } appendNewEdge(doc, prevStateId, SINK_NODE_ID, edgeToNextState, s, valueMap); } } } } doc.appendFooter(); } } private static class DelayedAssignmentsKey { private final String from; private final CFAEdge edge; private final ARGState state; public DelayedAssignmentsKey(String pFrom, CFAEdge pEdge, ARGState pState) { this.from = pFrom; this.edge = pEdge; this.state = pState; } @Override public int hashCode() { return Objects.hash(from, edge, state); } @Override public boolean equals(Object pObj) { if (this == pObj) { return true; } if (pObj instanceof DelayedAssignmentsKey) { DelayedAssignmentsKey other = (DelayedAssignmentsKey) pObj; return Objects.equals(from, other.from) && Objects.equals(edge, other.edge) && Objects.equals(state, other.state); } return false; } } private static class AssignsParameterOfOtherFunction implements Predicate<AAssignment> { private final CFAEdge edge; private final String qualifier; public AssignsParameterOfOtherFunction(CFAEdge pEdge) { edge = pEdge; String currentFunctionName = pEdge.getPredecessor().getFunctionName(); qualifier = Strings.isNullOrEmpty(currentFunctionName) ? "" : currentFunctionName + "::"; } @Override public boolean apply(AAssignment pArg0) { ALeftHandSide leftHandSide = pArg0.getLeftHandSide(); if (!(leftHandSide instanceof CLeftHandSide)) { return false; } CLeftHandSide cLeftHandSide = (CLeftHandSide) leftHandSide; return cLeftHandSide.accept(new CExpressionVisitor<Boolean, RuntimeException>() { @Override public Boolean visit(CArraySubscriptExpression pIastArraySubscriptExpression) throws RuntimeException { return pIastArraySubscriptExpression.getArrayExpression().accept(this) && pIastArraySubscriptExpression.getSubscriptExpression().accept(this); } @Override public Boolean visit(CFieldReference pIastFieldReference) throws RuntimeException { return pIastFieldReference.getFieldOwner().accept(this); } @Override public Boolean visit(CIdExpression pIastIdExpression) throws RuntimeException { CSimpleDeclaration declaration = pIastIdExpression.getDeclaration(); if (declaration instanceof CParameterDeclaration && edge instanceof FunctionCallEdge) { return declaration.getQualifiedName().startsWith(qualifier); } return true; } @Override public Boolean visit(CPointerExpression pPointerExpression) throws RuntimeException { return pPointerExpression.getOperand().accept(this); } @Override public Boolean visit(CComplexCastExpression pComplexCastExpression) throws RuntimeException { return pComplexCastExpression.getOperand().accept(this); } @Override public Boolean visit(CBinaryExpression pIastBinaryExpression) throws RuntimeException { return pIastBinaryExpression.getOperand1().accept(this) && pIastBinaryExpression.getOperand2().accept(this); } @Override public Boolean visit(CCastExpression pIastCastExpression) throws RuntimeException { return pIastCastExpression.getOperand().accept(this); } @Override public Boolean visit(CCharLiteralExpression pIastCharLiteralExpression) throws RuntimeException { return true; } @Override public Boolean visit(CFloatLiteralExpression pIastFloatLiteralExpression) throws RuntimeException { return true; } @Override public Boolean visit(CIntegerLiteralExpression pIastIntegerLiteralExpression) throws RuntimeException { return true; } @Override public Boolean visit(CStringLiteralExpression pIastStringLiteralExpression) throws RuntimeException { return true; } @Override public Boolean visit(CTypeIdExpression pIastTypeIdExpression) throws RuntimeException { return true; } @Override public Boolean visit(CUnaryExpression pIastUnaryExpression) throws RuntimeException { return pIastUnaryExpression.getOperand().accept(this); } @Override public Boolean visit(CImaginaryLiteralExpression pIastLiteralExpression) throws RuntimeException { return pIastLiteralExpression.getValue().accept(this); } }); } } }