OSDN Git Service

eclair snapshot
[android-x86/build.git] / tools / apicheck / src / com / android / apicheck / ApiCheck.java
1 /*
2  * Copyright (C) 2008 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
17 package com.android.apicheck;
18
19 import org.xml.sax.*;
20 import org.xml.sax.helpers.*;
21 import java.io.*;
22 import java.util.ArrayList;
23 import java.util.Stack;
24
25 public class ApiCheck {
26         // parse out and consume the -whatever command line flags
27         private static ArrayList<String[]> parseFlags(ArrayList<String> allArgs) {
28             ArrayList<String[]> ret = new ArrayList<String[]>();
29
30             int i;
31             for (i = 0; i < allArgs.size(); i++) {
32                 // flags with one value attached
33                 String flag = allArgs.get(i);
34                 if (flag.equals("-error")
35                         || flag.equals("-warning")
36                         || flag.equals("-hide")) {
37                     String[] arg = new String[2];
38                     arg[0] = flag;
39                     arg[1] = allArgs.get(++i);
40                     ret.add(arg);
41                 } else {
42                     // we've consumed all of the -whatever args, so we're done
43                     break;
44                 }
45             }
46
47             // i now points to the first non-flag arg; strip what came before
48             for (; i > 0; i--) {
49                 allArgs.remove(0);
50             }
51             return ret;
52         }
53
54         public static void main(String[] originalArgs) {
55             // translate to an ArrayList<String> for munging
56             ArrayList<String> args = new ArrayList<String>(originalArgs.length);
57             for (String a: originalArgs) {
58                 args.add(a);
59             }
60
61             ArrayList<String[]> flags = ApiCheck.parseFlags(args);
62             for (String[] a: flags) {
63                 if (a[0].equals("-error") || a[0].equals("-warning")
64                         || a[0].equals("-hide")) {
65                     try {
66                         int level = -1;
67                         if (a[0].equals("-error")) {
68                             level = Errors.ERROR;
69                         }
70                         else if (a[0].equals("-warning")) {
71                             level = Errors.WARNING;
72                         }
73                         else if (a[0].equals("-hide")) {
74                             level = Errors.HIDDEN;
75                         }
76                         Errors.setErrorLevel(Integer.parseInt(a[1]), level);
77                     }
78                     catch (NumberFormatException e) {
79                         System.err.println("Bad argument: " + a[0] + " " + a[1]);
80                         System.exit(2);
81                     }
82                 }
83             }
84
85             ApiCheck acheck = new ApiCheck();
86
87             ApiInfo oldApi = acheck.parseApi(args.get(0));
88             ApiInfo newApi = acheck.parseApi(args.get(1));
89
90             // only run the consistency check if we haven't had XML parse errors
91             if (!Errors.hadError) {
92                 oldApi.isConsistent(newApi);
93             }
94
95             Errors.printErrors();
96             System.exit(Errors.hadError ? 1 : 0);
97         }
98
99     public ApiInfo parseApi(String xmlFile) {
100         FileReader fileReader = null;
101         try {
102             XMLReader xmlreader = XMLReaderFactory.createXMLReader();
103             MakeHandler handler = new MakeHandler();
104             xmlreader.setContentHandler(handler);
105             xmlreader.setErrorHandler(handler);
106             fileReader = new FileReader(xmlFile);
107             xmlreader.parse(new InputSource(fileReader));
108             ApiInfo apiInfo = handler.getApi();
109             apiInfo.resolveSuperclasses();
110             return apiInfo;
111         } catch (SAXParseException e) {
112             Errors.error(Errors.PARSE_ERROR,
113                     new SourcePositionInfo(xmlFile, e.getLineNumber(), 0),
114                     e.getMessage());
115         } catch (Exception e) {
116             e.printStackTrace();
117             Errors.error(Errors.PARSE_ERROR,
118                     new SourcePositionInfo(xmlFile, 0, 0), e.getMessage());
119         } finally {
120             if (fileReader != null) {
121                 try {
122                     fileReader.close();
123                 } catch (IOException ignored) {}
124             }
125         }
126         return null;
127     }
128
129     private static class MakeHandler extends DefaultHandler {
130
131             private ApiInfo mApi;
132             private PackageInfo mCurrentPackage;
133             private ClassInfo mCurrentClass;
134             private AbstractMethodInfo mCurrentMethod;
135             private Stack<ClassInfo> mClassScope = new Stack<ClassInfo>();
136
137
138             public MakeHandler() {
139                 super();
140                 mApi = new ApiInfo();
141             }
142
143             @Override
144             public void startElement(String uri, String localName, String qName,
145                                      Attributes attributes) {
146                 if (qName.equals("package")) {
147                     mCurrentPackage = new PackageInfo(attributes.getValue("name"),
148                             SourcePositionInfo.fromXml(attributes.getValue("source")));
149                 } else if (qName.equals("class")
150                         || qName.equals("interface")) {
151                     // push the old outer scope for later recovery, then set
152                     // up the new current class object
153                     mClassScope.push(mCurrentClass);
154                     mCurrentClass = new ClassInfo(attributes.getValue("name"),
155                                                   mCurrentPackage,
156                                                   attributes.getValue("extends") ,
157                                                   qName.equals("interface"),
158                                                   Boolean.valueOf(
159                                                       attributes.getValue("abstract")),
160                                                   Boolean.valueOf(
161                                                       attributes.getValue("static")),
162                                                   Boolean.valueOf(
163                                                       attributes.getValue("final")),
164                                                   attributes.getValue("deprecated"),
165                                                   attributes.getValue("visibility"),
166                                                   SourcePositionInfo.fromXml(attributes.getValue("source")),
167                                                   mCurrentClass);
168                 } else if (qName.equals("method")) {
169                     mCurrentMethod = new MethodInfo(attributes.getValue("name"),
170                                                     attributes.getValue("return") ,
171                                                     Boolean.valueOf(
172                                                         attributes.getValue("abstract")),
173                                                     Boolean.valueOf(
174                                                         attributes.getValue("native")),
175                                                     Boolean.valueOf(
176                                                         attributes.getValue("synchronized")),
177                                                     Boolean.valueOf(
178                                                         attributes.getValue("static")),
179                                                     Boolean.valueOf(
180                                                         attributes.getValue("final")),
181                                                     attributes.getValue("deprecated"),
182                                                     attributes.getValue("visibility"),
183                                                     SourcePositionInfo.fromXml(attributes.getValue("source")),
184                                                     mCurrentClass);
185                 } else if (qName.equals("constructor")) {
186                     mCurrentMethod = new ConstructorInfo(attributes.getValue("name"),
187                                                          attributes.getValue("type") ,
188                                                          Boolean.valueOf(
189                                                              attributes.getValue("static")),
190                                                          Boolean.valueOf(
191                                                              attributes.getValue("final")),
192                                                          attributes.getValue("deprecated"),
193                                                          attributes.getValue("visibility"),
194                                                          SourcePositionInfo.fromXml(attributes.getValue("source")),
195                                                          mCurrentClass);
196                 } else if (qName.equals("field")) {
197                     FieldInfo fInfo = new FieldInfo(attributes.getValue("name"),
198                                                     attributes.getValue("type") ,
199                                                     Boolean.valueOf(
200                                                         attributes.getValue("transient")),
201                                                     Boolean.valueOf(
202                                                         attributes.getValue("volatile")),
203                                                     attributes.getValue("value"),
204                                                     Boolean.valueOf(
205                                                         attributes.getValue("static")),
206                                                     Boolean.valueOf(
207                                                         attributes.getValue("final")),
208                                                     attributes.getValue("deprecated"),
209                                                     attributes.getValue("visibility"),
210                                                     SourcePositionInfo.fromXml(attributes.getValue("source")),
211                                                     mCurrentClass);
212                     mCurrentClass.addField(fInfo);
213                 } else if (qName.equals("parameter")) {
214                     mCurrentMethod.addParameter(new ParameterInfo(attributes.getValue("type"),
215                                                                   attributes.getValue("name")));
216                 } else if (qName.equals("exception")) {
217                     mCurrentMethod.addException(attributes.getValue("type"));
218                 } else if (qName.equals("implements")) {
219                     mCurrentClass.addInterface(attributes.getValue("name"));
220                 }
221             }
222
223             @Override
224             public void endElement(String uri, String localName, String qName) {
225                 if (qName.equals("method")) {
226                     mCurrentClass.addMethod((MethodInfo) mCurrentMethod);
227                 } else if (qName.equals("constructor")) {
228                     mCurrentClass.addConstructor((ConstructorInfo) mCurrentMethod);
229                 } else if (qName.equals("class")
230                         || qName.equals("interface")) {
231                     mCurrentPackage.addClass(mCurrentClass);
232                     mCurrentClass = mClassScope.pop();
233                 } else if (qName.equals("package")){
234                     mApi.addPackage(mCurrentPackage);
235                 }
236             }
237             public ApiInfo getApi() {
238                 return mApi;
239             }
240         }
241 }