1/*
2 * Copyright (C) 2010 Google Inc.
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
17package com.google.doclava;
18
19import com.google.clearsilver.jsilver.data.Data;
20
21import java.util.*;
22
23public class TodoFile {
24
25  public static final String MISSING = "No description text";
26
27  public static boolean areTagsUseful(InheritedTags tags) {
28    while (tags != null) {
29      if (areTagsUseful(tags.tags())) {
30        return true;
31      }
32      tags = tags.inherited();
33    }
34    return false;
35  }
36
37  public static boolean areTagsUseful(TagInfo[] tags) {
38    for (TagInfo t : tags) {
39      if ("Text".equals(t.name()) && t.text().trim().length() != 0) {
40        return true;
41      }
42      if ("@inheritDoc".equals(t.name())) {
43        return true;
44      }
45    }
46    return false;
47  }
48
49  public static void setHDF(Data data, String base, SourcePositionInfo pos, String name,
50      String descr) {
51    data.setValue(base + ".pos", pos.toString());
52    data.setValue(base + ".name", name);
53    data.setValue(base + ".descr", descr);
54  }
55
56  static class PackageStats {
57    String name;
58    public int total;
59    public int errors;
60  }
61
62  public static String percent(int a, int b) {
63    return "" + Math.round((((b - a) / (float) b)) * 100) + "%";
64  }
65
66  public static void writeTodoFile(String filename) {
67    Data data = Doclava.makeHDF();
68    Doclava.setPageTitle(data, "Missing Documentation");
69    TreeMap<String, PackageStats> packageStats = new TreeMap<String, PackageStats>();
70
71    ClassInfo[] classes = Converter.rootClasses();
72    Arrays.sort(classes);
73
74    int classIndex = 0;
75
76    for (ClassInfo cl : classes) {
77      if (cl.isHiddenOrRemoved()){
78        continue;
79      }
80
81      String classBase = "classes." + classIndex;
82
83      String base = classBase + ".errors.";
84      int errors = 0;
85      int total = 1;
86
87      if (!areTagsUseful(cl.inlineTags())) {
88        setHDF(data, base + errors, cl.position(), "&lt;class comment&gt;", MISSING);
89        errors++;
90      }
91
92
93      for (MethodInfo m : cl.constructors()) {
94        boolean good = true;
95        total++;
96        if (m.checkLevel()) {
97          if (!areTagsUseful(m.inlineTags())) {
98            setHDF(data, base + errors, m.position(), m.prettySignature(), MISSING);
99            good = false;
100          }
101        }
102        if (!good) {
103          errors++;
104        }
105      }
106
107      for (MethodInfo m : cl.selfMethods()) {
108        boolean good = true;
109        total++;
110        if (m.checkLevel()) {
111          if (!areTagsUseful(m.inlineTags())) {
112            setHDF(data, base + errors, m.position(), m.name() + m.prettySignature(), MISSING);
113            good = false;
114          }
115        }
116        if (!good) {
117          errors++;
118        }
119      }
120
121
122      for (FieldInfo f : cl.enumConstants()) {
123        boolean good = true;
124        total++;
125        if (f.checkLevel()) {
126          if (!areTagsUseful(f.inlineTags())) {
127            setHDF(data, base + errors, f.position(), f.name(), MISSING);
128            good = false;
129          }
130        }
131        if (!good) {
132          errors++;
133        }
134      }
135
136      for (FieldInfo f : cl.selfFields()) {
137        boolean good = true;
138        total++;
139        if (f.checkLevel()) {
140          if (!areTagsUseful(f.inlineTags())) {
141            setHDF(data, base + errors, f.position(), f.name(), MISSING);
142            good = false;
143          }
144        }
145        if (!good) {
146          errors++;
147        }
148      }
149
150      if (errors > 0) {
151        data.setValue(classBase + ".qualified", cl.qualifiedName());
152        data.setValue(classBase + ".errorCount", "" + errors);
153        data.setValue(classBase + ".totalCount", "" + total);
154        data.setValue(classBase + ".percentGood", percent(errors, total));
155      }
156
157      PackageInfo pkg = cl.containingPackage();
158      String pkgName = pkg != null ? pkg.name() : "";
159      PackageStats ps = packageStats.get(pkgName);
160      if (ps == null) {
161        ps = new PackageStats();
162        ps.name = pkgName;
163        packageStats.put(pkgName, ps);
164      }
165      ps.total += total;
166      ps.errors += errors;
167
168      classIndex++;
169    }
170
171    int allTotal = 0;
172    int allErrors = 0;
173
174    int i = 0;
175    for (PackageStats ps : packageStats.values()) {
176      data.setValue("packages." + i + ".name", "" + ps.name);
177      data.setValue("packages." + i + ".errorCount", "" + ps.errors);
178      data.setValue("packages." + i + ".totalCount", "" + ps.total);
179      data.setValue("packages." + i + ".percentGood", percent(ps.errors, ps.total));
180
181      allTotal += ps.total;
182      allErrors += ps.errors;
183
184      i++;
185    }
186
187    data.setValue("all.errorCount", "" + allErrors);
188    data.setValue("all.totalCount", "" + allTotal);
189    data.setValue("all.percentGood", percent(allErrors, allTotal));
190
191    ClearPage.write(data, "todo.cs", filename, true);
192  }
193}
194