• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.currysrc.api.process.ast;
17 
18 import java.util.LinkedHashMap;
19 import java.util.Map;
20 import java.util.Map.Entry;
21 import org.eclipse.jdt.core.dom.BodyDeclaration;
22 
23 /**
24  * Associates a {@link BodyDeclaration} (identified by a {@link BodyDeclarationLocator}) with some
25  * data, represented as a {@link Mapping}.
26  *
27  * @param <T> the type of data that can be associated with a {@link BodyDeclarationLocator}.
28  */
29 public class BodyDeclarationLocatorStore<T> {
30 
31   private final Map<BodyDeclarationLocator, T> locator2Data;
32 
BodyDeclarationLocatorStore()33   public BodyDeclarationLocatorStore() {
34     locator2Data = new LinkedHashMap<>();
35   }
36 
37   /**
38    * Adds a mapping between a {@link BodyDeclarationLocator} and some data.
39    *
40    * <p>If two of more {@link BodyDeclarationLocator} instances are added that will match the
41    * same {@link BodyDeclaration} then the first one added will take precedence.
42    *
43    * <p>It is an error to add the same {@link BodyDeclarationLocator} more than once.
44    */
add(BodyDeclarationLocator locator, T data)45   public void add(BodyDeclarationLocator locator, T data) {
46     T existing = locator2Data.putIfAbsent(locator, data);
47     if (existing != null) {
48       throw new IllegalStateException(
49           "Locator " + locator + " already has existing mapping: " + existing);
50     }
51   }
52 
53   /**
54    * Finds the data associated with the supplied {@link BodyDeclaration}.
55    *
56    * <p>This iterates through the list of mappings (in insertion order). For each mapping the
57    * {@link BodyDeclarationLocator} is checked to see if it matches the {@code declaration}. If it
58    * does match then the associated data is returned, otherwise the next mapping is checked. If no
59    * mappings matched then null is returned.
60    *
61    * @param declaration the {@link BodyDeclaration} whose associated data is required.
62    * @return null if there is no data associated with the supplied {@link BodyDeclaration},
63    * otherwise the data provided with the matching {@link BodyDeclarationLocator}.
64    */
find(BodyDeclaration declaration)65   public T find(BodyDeclaration declaration) {
66     for (Entry<BodyDeclarationLocator, T> entry : locator2Data.entrySet()) {
67       if (entry.getKey().matches(declaration)) {
68         return entry.getValue();
69       }
70     }
71 
72     return null;
73   }
74 
75   public static class Mapping<T> {
76     private final BodyDeclarationLocator locator;
77     private final T value;
78 
Mapping(BodyDeclarationLocator locator, T value)79     private Mapping(BodyDeclarationLocator locator, T value) {
80       this.locator = locator;
81       this.value = value;
82     }
83 
getLocator()84     public BodyDeclarationLocator getLocator() {
85       return locator;
86     }
87 
getValue()88     public T getValue() {
89       return value;
90     }
91   }
92 
93   /**
94    * Finds the mapping associated with the supplied {@link BodyDeclaration}.
95    *
96    * <p>This iterates through the list of mappings (in insertion order). For each mapping the
97    * {@link BodyDeclarationLocator} is checked to see if it matches the {@code declaration}. If it
98    * does match then the mapping is returned, otherwise the next mapping is checked. If no mappings
99    * matched then null is returned.
100    *
101    * @param declaration the {@link BodyDeclaration} whose associated data is required.
102    * @return null if there is no mapping associated with the supplied {@link BodyDeclaration},
103    * otherwise the mapping provided with the matching {@link BodyDeclarationLocator}.
104    */
findMapping(BodyDeclaration declaration)105   public Mapping<T> findMapping(BodyDeclaration declaration) {
106     for (Entry<BodyDeclarationLocator, T> entry : locator2Data.entrySet()) {
107       if (entry.getKey().matches(declaration)) {
108         return new Mapping<>(entry.getKey(), entry.getValue());
109       }
110     }
111 
112     return null;
113   }
114 }
115