@@ -17,6 +17,9 @@ import java.util.Map;
|
|||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.ide.vscode.commons.util.Assert;
|
import org.springframework.ide.vscode.commons.util.Assert;
|
||||||
import org.springframework.ide.vscode.commons.util.StringUtil;
|
import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||||
import org.springframework.ide.vscode.commons.util.text.IDocument;
|
import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||||
@@ -41,6 +44,8 @@ import com.google.common.collect.Multimap;
|
|||||||
* @author Kris De Volder
|
* @author Kris De Volder
|
||||||
*/
|
*/
|
||||||
public class ASTTypeCache implements ITypeCollector {
|
public class ASTTypeCache implements ITypeCollector {
|
||||||
|
|
||||||
|
private static Logger log = LoggerFactory.getLogger(ASTTypeCache.class);
|
||||||
|
|
||||||
public interface NodeTypes {
|
public interface NodeTypes {
|
||||||
Collection<Node> getNodes(YType type);
|
Collection<Node> getNodes(YType type);
|
||||||
@@ -88,7 +93,7 @@ public class ASTTypeCache implements ITypeCollector {
|
|||||||
/**
|
/**
|
||||||
* Collects types for the current session.
|
* Collects types for the current session.
|
||||||
*/
|
*/
|
||||||
private ImmutableMap.Builder<Node, YType> currentTypes = null;
|
private Map<Node, Pair<YType, YamlPath>> currentTypes = null;
|
||||||
|
|
||||||
private final Set<YType> interestingTypes = new HashSet<>();
|
private final Set<YType> interestingTypes = new HashSet<>();
|
||||||
private final Map<String, NodeTypes> typeIndex = new HashMap<>();
|
private final Map<String, NodeTypes> typeIndex = new HashMap<>();
|
||||||
@@ -97,14 +102,18 @@ public class ASTTypeCache implements ITypeCollector {
|
|||||||
public void beginCollecting(YamlFileAST ast) {
|
public void beginCollecting(YamlFileAST ast) {
|
||||||
Assert.isNull("A session is already active. Concurrency isn't supported by ITypeCollector protocol", currentTypes);
|
Assert.isNull("A session is already active. Concurrency isn't supported by ITypeCollector protocol", currentTypes);
|
||||||
this.currentAst = ast;
|
this.currentAst = ast;
|
||||||
this.currentTypes = ImmutableMap.builder();
|
this.currentTypes = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void endCollecting(YamlFileAST ast) {
|
public synchronized void endCollecting(YamlFileAST ast) {
|
||||||
Assert.isLegal(currentAst==ast);
|
Assert.isLegal(currentAst==ast);
|
||||||
String uri = ast.getDocument().getUri();
|
String uri = ast.getDocument().getUri();
|
||||||
typeIndex.put(uri, new NodeTypesImpl(currentAst, currentTypes.build()));
|
ImmutableMap.Builder<Node, YType> nodeTypes = ImmutableMap.builder();
|
||||||
|
for (Entry<Node, Pair<YType, YamlPath>> entry : currentTypes.entrySet()) {
|
||||||
|
nodeTypes.put(entry.getKey(), entry.getValue().getLeft());
|
||||||
|
}
|
||||||
|
typeIndex.put(uri, new NodeTypesImpl(currentAst, nodeTypes.build()));
|
||||||
this.currentAst = null;
|
this.currentAst = null;
|
||||||
this.currentTypes = null;
|
this.currentTypes = null;
|
||||||
}
|
}
|
||||||
@@ -112,7 +121,25 @@ public class ASTTypeCache implements ITypeCollector {
|
|||||||
@Override
|
@Override
|
||||||
public void accept(Node node, YType type, YamlPath path) {
|
public void accept(Node node, YType type, YamlPath path) {
|
||||||
if (interestingTypes.contains(type)) {
|
if (interestingTypes.contains(type)) {
|
||||||
currentTypes.put(node, type);
|
Pair<YType, YamlPath> existing = currentTypes.get(node);
|
||||||
|
if (existing!=null) {
|
||||||
|
//A second time assinging type to the same node. This is possible when anchors / references
|
||||||
|
// are used (this makes parts of the tree 'shared').
|
||||||
|
YType oldType = existing.getLeft();
|
||||||
|
if (oldType.equals(type)) {
|
||||||
|
//If the types are the same nothing is lost by dropping the extra assignment.
|
||||||
|
} else {
|
||||||
|
//different types trying to be assigned to same node.
|
||||||
|
//This is possible in theory when 'anchors and references' are in use.
|
||||||
|
//We hope this doesn't happen in practice. We'll log it in case it does.
|
||||||
|
log.warn("Ignore assignment of type for: {}", path);
|
||||||
|
log.warn(" Already assigned at: {}", existing.getRight());
|
||||||
|
log.warn(" Previous type : {}", existing.getLeft());
|
||||||
|
log.warn(" New type : {}", type);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
currentTypes.put(node, Pair.of(type, path));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -266,6 +266,26 @@ public class ConcourseEditorTest {
|
|||||||
" git2::Resource\n"
|
" git2::Resource\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void complexOutlineWithAnchors() throws Exception {
|
||||||
|
harness.enableHierarchicalDocumentSymbols(true);
|
||||||
|
//See: https://github.com/spring-projects/sts4/issues/483
|
||||||
|
|
||||||
|
Editor editor = harness.newEditorFromClasspath("/workspace/gh_483_pipeline.yml");
|
||||||
|
|
||||||
|
editor.assertHierarchicalDocumentSymbols(
|
||||||
|
"resource_types::Resource Types\n" +
|
||||||
|
" concourse-pipeline-resource::Resource Type\n" +
|
||||||
|
" slack-notification::Resource Type\n" +
|
||||||
|
"resources::Resources\n" +
|
||||||
|
" git-ci-pipeline::Resource\n" +
|
||||||
|
" concourse::Resource\n" +
|
||||||
|
" mattermost-notify::Resource\n" +
|
||||||
|
"jobs::Jobs\n" +
|
||||||
|
" pipeline install::Job\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void reconcileStructuralProblems() throws Exception {
|
public void reconcileStructuralProblems() throws Exception {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user