| // Copyright (C) 2015 The Android Open Source Project |
| // |
| // 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. |
| |
| package validate |
| |
| import ( |
| "android.googlesource.com/platform/tools/gpu/api/semantic" |
| "android.googlesource.com/platform/tools/gpu/parse" |
| ) |
| |
| // noUnusedTypes verifies that all declared types are used. |
| func noUnusedTypes(apiName string, api *semantic.API) []error { |
| used := map[semantic.Type]bool{} |
| tokens := map[semantic.Type]parse.Token{} |
| |
| // Gather all declared types |
| for _, t := range api.Classes { |
| used[t] = false |
| tokens[t] = t.AST.CST.Token() |
| } |
| for _, t := range api.Enums { |
| used[t] = false |
| tokens[t] = t.AST.CST.Token() |
| } |
| for _, t := range api.Pseudonyms { |
| used[t] = false |
| tokens[t] = t.AST.CST.Token() |
| } |
| |
| // Functions for marking types as used |
| var markUsed func(t semantic.Type) |
| markUsed = func(t semantic.Type) { |
| if used[t] { |
| return |
| } |
| used[t] = true |
| switch t := t.(type) { |
| case *semantic.Reference: |
| markUsed(t.To) |
| case *semantic.Slice: |
| markUsed(t.To) |
| case *semantic.Map: |
| markUsed(t.ValueType) |
| markUsed(t.KeyType) |
| case *semantic.Pointer: |
| markUsed(t.To) |
| case *semantic.Pseudonym: |
| markUsed(t.To) |
| case *semantic.Class: |
| for _, f := range t.Fields { |
| markUsed(f.Type) |
| } |
| for _, e := range t.Extends { |
| markUsed(e) |
| } |
| case *semantic.Enum: |
| for _, e := range t.Extends { |
| markUsed(e) |
| } |
| } |
| } |
| var traverseExpression func(e semantic.Expression) |
| traverseExpression = func(e semantic.Expression) { |
| switch e := e.(type) { |
| case *semantic.UnaryOp: |
| traverseExpression(e.Expression) |
| case *semantic.BinaryOp: |
| traverseExpression(e.LHS) |
| traverseExpression(e.RHS) |
| case *semantic.ClassInitializer: |
| markUsed(e.Class) |
| // TODO: Insert more expression cases |
| } |
| } |
| var traverseStatement func(s interface{}) |
| traverseStatement = func(s interface{}) { |
| switch s := s.(type) { |
| case *semantic.DeclareLocal: |
| traverseExpression(s.Local.Value) |
| case *semantic.Assign: |
| traverseExpression(s.LHS) |
| traverseExpression(s.RHS) |
| case *semantic.Call: |
| for _, a := range s.Arguments { |
| traverseExpression(a) |
| } |
| // TODO: Insert more statement cases |
| } |
| } |
| var traverseFunction func(f *semantic.Function) |
| traverseFunction = func(f *semantic.Function) { |
| for _, p := range f.FullParameters { |
| markUsed(p.Type) |
| } |
| for _, s := range f.Block.Statements { |
| traverseStatement(s) |
| } |
| } |
| |
| // Traverse the API finding all used types |
| for _, g := range api.Globals { |
| markUsed(g.Type) |
| } |
| for _, f := range api.Functions { |
| traverseFunction(f) |
| } |
| for _, c := range api.Classes { |
| for _, m := range c.Methods { |
| traverseFunction(m) |
| } |
| } |
| for _, c := range api.Pseudonyms { |
| for _, m := range c.Methods { |
| traverseFunction(m) |
| } |
| } |
| |
| // Report all types declared but not used as errors |
| errors := []error{} |
| for t, used := range used { |
| if !used { |
| e := err(apiName, tokens[t], "%s declared but never used", t.Typename()) |
| errors = append(errors, e) |
| } |
| } |
| return errors |
| } |